mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
D4CRIS-416 introduce model class to manage patch operation deserialization
This commit is contained in:
@@ -23,6 +23,7 @@ import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.atteo.evo.inflector.English;
|
||||
import org.dspace.app.rest.converter.JsonPatchConverter;
|
||||
import org.dspace.app.rest.exception.PaginationException;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
||||
@@ -35,6 +36,7 @@ import org.dspace.app.rest.model.LinkRest;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||
import org.dspace.app.rest.repository.LinkRestRepository;
|
||||
@@ -49,8 +51,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.rest.webmvc.ControllerUtils;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.data.rest.webmvc.json.patch.JsonPatchPatchConverter;
|
||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
@@ -263,7 +263,7 @@ public class RestResourceController implements InitializingBean {
|
||||
DSpaceRestRepository<DirectlyAddressableRestModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
DirectlyAddressableRestModel modelObject = null;
|
||||
try {
|
||||
JsonPatchPatchConverter patchConverter = new JsonPatchPatchConverter(mapper);
|
||||
JsonPatchConverter patchConverter = new JsonPatchConverter(mapper);
|
||||
Patch patch = patchConverter.convert(jsonNode);
|
||||
modelObject = repository.patch(request, apiCategory, model, id, patch);
|
||||
}
|
||||
|
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.dspace.app.rest.model.patch.AddOperation;
|
||||
import org.dspace.app.rest.model.patch.CopyOperation;
|
||||
import org.dspace.app.rest.model.patch.FromOperation;
|
||||
import org.dspace.app.rest.model.patch.JsonValueEvaluator;
|
||||
import org.dspace.app.rest.model.patch.MoveOperation;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.patch.RemoveOperation;
|
||||
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
/**
|
||||
*
|
||||
* Convert {@link JsonNode}s containing JSON Patch to/from {@link Patch} objects.
|
||||
*
|
||||
* Based on {@link org.springframework.data.rest.webmvc.json.patch.JsonPatchPatchConverter}
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class JsonPatchConverter implements PatchConverter<JsonNode> {
|
||||
|
||||
private final @Nonnull ObjectMapper mapper;
|
||||
|
||||
public JsonPatchConverter(ObjectMapper mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Patch} object given a JsonNode.
|
||||
*
|
||||
* @param jsonNode a JsonNode containing the JSON Patch
|
||||
* @return a {@link Patch}
|
||||
*/
|
||||
public Patch convert(JsonNode jsonNode) {
|
||||
|
||||
if (!(jsonNode instanceof ArrayNode)) {
|
||||
throw new IllegalArgumentException("JsonNode must be an instance of ArrayNode");
|
||||
}
|
||||
|
||||
ArrayNode opNodes = (ArrayNode) jsonNode;
|
||||
List<Operation> ops = new ArrayList<Operation>(opNodes.size());
|
||||
|
||||
for (Iterator<JsonNode> elements = opNodes.elements(); elements.hasNext();) {
|
||||
|
||||
JsonNode opNode = elements.next();
|
||||
|
||||
String opType = opNode.get("op").textValue();
|
||||
String path = opNode.get("path").textValue();
|
||||
|
||||
JsonNode valueNode = opNode.get("value");
|
||||
Object value = valueFromJsonNode(path, valueNode);
|
||||
String from = opNode.has("from") ? opNode.get("from").textValue() : null;
|
||||
|
||||
//IDEA maybe if the operation have a universal name the PatchOperation can be retrieve here not in WorkspaceItemRestRepository.evaluatePatch
|
||||
if (opType.equals("replace")) {
|
||||
ops.add(new ReplaceOperation(path, value));
|
||||
} else if (opType.equals("remove")) {
|
||||
ops.add(new RemoveOperation(path));
|
||||
} else if (opType.equals("add")) {
|
||||
ops.add(new AddOperation(path, value));
|
||||
} else if (opType.equals("copy")) {
|
||||
ops.add(new CopyOperation(path, from));
|
||||
} else if (opType.equals("move")) {
|
||||
ops.add(new MoveOperation(path, from));
|
||||
} else {
|
||||
throw new PatchException("Unrecognized operation type: " + opType);
|
||||
}
|
||||
}
|
||||
|
||||
return new Patch(ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a {@link Patch} as a {@link JsonNode}.
|
||||
*
|
||||
* @param patch the patch
|
||||
* @return a {@link JsonNode} containing JSON Patch.
|
||||
*/
|
||||
public JsonNode convert(Patch patch) {
|
||||
|
||||
List<Operation> operations = patch.getOperations();
|
||||
JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
|
||||
ArrayNode patchNode = nodeFactory.arrayNode();
|
||||
|
||||
for (Operation operation : operations) {
|
||||
|
||||
ObjectNode opNode = nodeFactory.objectNode();
|
||||
opNode.set("op", nodeFactory.textNode(operation.getOp()));
|
||||
opNode.set("path", nodeFactory.textNode(operation.getPath()));
|
||||
|
||||
if (operation instanceof FromOperation) {
|
||||
|
||||
FromOperation fromOp = (FromOperation) operation;
|
||||
opNode.set("from", nodeFactory.textNode(fromOp.getFrom()));
|
||||
}
|
||||
|
||||
Object value = operation.getValue();
|
||||
|
||||
if (value != null) {
|
||||
opNode.set("value", mapper.valueToTree(value));
|
||||
}
|
||||
|
||||
patchNode.add(opNode);
|
||||
}
|
||||
|
||||
return patchNode;
|
||||
}
|
||||
|
||||
private Object valueFromJsonNode(String path, JsonNode valueNode) {
|
||||
|
||||
if (valueNode == null || valueNode.isNull()) {
|
||||
return null;
|
||||
} else if (valueNode.isTextual()) {
|
||||
return valueNode.asText();
|
||||
} else if (valueNode.isFloatingPointNumber()) {
|
||||
return valueNode.asDouble();
|
||||
} else if (valueNode.isBoolean()) {
|
||||
return valueNode.asBoolean();
|
||||
} else if (valueNode.isInt()) {
|
||||
return valueNode.asInt();
|
||||
} else if (valueNode.isLong()) {
|
||||
return valueNode.asLong();
|
||||
} else if (valueNode.isObject() || (valueNode.isArray())) {
|
||||
return new JsonValueEvaluator(mapper, valueNode);
|
||||
}
|
||||
|
||||
throw new PatchException(
|
||||
String.format("Unrecognized valueNode type at path %s and value node %s.", path, valueNode));
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A strategy interface for producing {@link Patch} instances from a patch document representation (such as JSON Patch)
|
||||
* and rendering a Patch to a patch document representation. This decouples the {@link Patch} class from any specific
|
||||
* patch format or library that holds the representation.
|
||||
* </p>
|
||||
* <p>
|
||||
* For example, if the {@link Patch} is to be represented as JSON Patch, the representation type could be
|
||||
* {@link JsonNode} or some other JSON library's type that holds a JSON document.
|
||||
* </p>
|
||||
*
|
||||
* Based on {@link org.springframework.data.rest.webmvc.json.patch.PatchConverter}
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface PatchConverter<T> {
|
||||
|
||||
/**
|
||||
* Convert a patch document representation to a {@link Patch}.
|
||||
*
|
||||
* @param patchRepresentation the representation of a patch.
|
||||
* @return the {@link Patch} object that the document represents.
|
||||
*/
|
||||
Patch convert(T patchRepresentation);
|
||||
|
||||
/**
|
||||
* Convert a {@link Patch} to a representation object.
|
||||
*
|
||||
* @param patch the {@link Patch} to convert.
|
||||
* @return the patch representation object.
|
||||
*/
|
||||
T convert(Patch patch);
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "add" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class AddOperation extends Operation {
|
||||
|
||||
public AddOperation(String path, Object value) {
|
||||
super("add", path, value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "copy" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class CopyOperation extends FromOperation {
|
||||
|
||||
public CopyOperation(String path, String from) {
|
||||
super("copy", path, from);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "from" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public abstract class FromOperation extends Operation {
|
||||
|
||||
private final String from;
|
||||
|
||||
/**
|
||||
* Constructs the operation
|
||||
*
|
||||
* @param op The name of the operation to perform. (e.g., 'copy')
|
||||
* @param path The operation's target path. (e.g., '/foo/bar/4')
|
||||
* @param from The operation's source path. (e.g., '/foo/bar/5')
|
||||
*/
|
||||
public FromOperation(String op, String path, String from) {
|
||||
super(op, path);
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* {@link LateObjectEvaluator} implementation that assumes values represented as JSON objects.
|
||||
*
|
||||
* Based on {@link org.springframework.data.rest.webmvc.json.patch.JsonLateObjectEvaluator}
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class JsonValueEvaluator implements LateObjectEvaluator {
|
||||
|
||||
private final @Nonnull ObjectMapper mapper;
|
||||
private final @Nonnull JsonNode valueNode;
|
||||
|
||||
public JsonValueEvaluator(ObjectMapper mapper, JsonNode valueNode) {
|
||||
this.mapper = mapper;
|
||||
this.valueNode = valueNode;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator#evaluate(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Object evaluate(Class<T> type) {
|
||||
|
||||
try {
|
||||
return mapper.readValue(valueNode.traverse(), type);
|
||||
} catch (Exception e) {
|
||||
throw new PatchException(String.format("Could not read %s into %s!", valueNode, type), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "move" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class MoveOperation extends FromOperation {
|
||||
|
||||
public MoveOperation(String path, String from) {
|
||||
super("move", path, from);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
*
|
||||
* Abstract base class representing and providing support methods for patch operations.
|
||||
*
|
||||
* Based on {@link org.springframework.data.rest.webmvc.json.patch.PatchOperation}
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public abstract class Operation {
|
||||
|
||||
protected String op;
|
||||
protected String path;
|
||||
protected Object value;
|
||||
|
||||
public Operation(String operation, String path) {
|
||||
this.op = operation;
|
||||
this.path = path;
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
public Operation(String operation, String path, Object value) {
|
||||
this.op = operation;
|
||||
this.path = path;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getOp() {
|
||||
return op;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Represents a Patch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class (and {@link Operation} capture the definition of a patch, but are not coupled to any specific patch
|
||||
* representation.
|
||||
* </p>
|
||||
*
|
||||
* Based on {@link org.springframework.data.rest.webmvc.json.patch.Patch}
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class Patch {
|
||||
|
||||
private final List<Operation> operations;
|
||||
|
||||
public Patch(List<Operation> operations) {
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of operations that make up this patch.
|
||||
*/
|
||||
public int size() {
|
||||
return operations.size();
|
||||
}
|
||||
|
||||
public List<Operation> getOperations() {
|
||||
return operations;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "remove" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class RemoveOperation extends Operation {
|
||||
|
||||
public RemoveOperation(String path) {
|
||||
super("remove", path);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.patch;
|
||||
|
||||
/**
|
||||
* Operation to track the "replace" operation to the given "path".
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class ReplaceOperation extends Operation {
|
||||
|
||||
public ReplaceOperation(String path, Object value) {
|
||||
super("replace", path, value);
|
||||
}
|
||||
|
||||
}
|
@@ -17,6 +17,7 @@ import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.DirectlyAddressableRestModel;
|
||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
@@ -25,7 +26,6 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
@@ -21,6 +21,8 @@ import org.dspace.app.rest.converter.WorkspaceItemConverter;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||
import org.dspace.app.rest.model.hateoas.WorkspaceItemResource;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||
import org.dspace.app.rest.submit.AbstractRestProcessingStep;
|
||||
import org.dspace.app.rest.submit.SubmissionService;
|
||||
@@ -49,8 +51,6 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchOperation;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -242,10 +242,10 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
|
||||
@Override
|
||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, Integer id, Patch patch) throws SQLException, AuthorizeException {
|
||||
List<PatchOperation> operations = patch.getOperations();
|
||||
List<Operation> operations = patch.getOperations();
|
||||
WorkspaceItemRest wsi = findOne(id);
|
||||
WorkspaceItem source = wis.find(context, id);
|
||||
for(PatchOperation op : operations) {
|
||||
for(Operation op : operations) {
|
||||
//the value in the position 0 is a null value
|
||||
String[] path = op.getPath().substring(1).split("/",3);
|
||||
if(OPERATION_PATH_SECTIONS.equals(path[0])) {
|
||||
|
Reference in New Issue
Block a user