From 16cb7daeafbb438970819beba9d23365f859ace2 Mon Sep 17 00:00:00 2001 From: MMilosz Date: Mon, 27 May 2024 09:12:12 +0200 Subject: [PATCH] fix: `replace` PATCH request on /metadata now supports multiple values --- .../DSpaceObjectMetadataPatchUtils.java | 32 ++++++++++++---- .../DSpaceObjectMetadataReplaceOperation.java | 38 ++++++++++++++++--- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataPatchUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataPatchUtils.java index 954cc844f237..566bb7cdc184 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataPatchUtils.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataPatchUtils.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -50,32 +52,46 @@ private DSpaceObjectMetadataPatchUtils() { * @return MetadataValueRest extracted from json in operation value */ protected MetadataValueRest extractMetadataValueFromOperation(Operation operation) { - MetadataValueRest metadataValue = null; + return extractMetadataValueListFromOperation(operation).get(0); + } + + /** + * Extract metadataValue from Operation by parsing the json and mapping it to a MetadataValueRest + * @param operation Operation whose value is begin parsed + * @return MetadataValueRest extracted from json in operation value + */ + protected List extractMetadataValueListFromOperation(Operation operation) { + List metadataValueList = new ArrayList<>(); try { if (operation.getValue() != null) { if (operation.getValue() instanceof JsonValueEvaluator) { JsonNode valueNode = ((JsonValueEvaluator) operation.getValue()).getValueNode(); if (valueNode.isArray()) { - metadataValue = objectMapper.treeToValue(valueNode.get(0), MetadataValueRest.class); + for (JsonNode node : valueNode) { + MetadataValueRest metadataValue = objectMapper.treeToValue(node, MetadataValueRest.class); + metadataValueList.add(metadataValue); + } } else { - metadataValue = objectMapper.treeToValue(valueNode, MetadataValueRest.class); + MetadataValueRest metadataValue = objectMapper.treeToValue(valueNode, MetadataValueRest.class); + metadataValueList.add(metadataValue); } } if (operation.getValue() instanceof String) { String valueString = (String) operation.getValue(); - metadataValue = new MetadataValueRest(); + MetadataValueRest metadataValue = new MetadataValueRest(); metadataValue.setValue(valueString); + metadataValueList.add(metadataValue); } } } catch (IOException e) { throw new DSpaceBadRequestException("IOException in " + - "DspaceObjectMetadataOperation.extractMetadataValueFromOperation trying to map json from " + - "operation.value to MetadataValue class.", e); + "DspaceObjectMetadataOperation.extractMetadataValueFromOperation trying to map json from " + + "operation.value to MetadataValue class.", e); } - if (metadataValue == null) { + if (metadataValueList.isEmpty()) { throw new DSpaceBadRequestException("Could not extract MetadataValue Object from Operation"); } - return metadataValue; + return metadataValueList; } /** diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataReplaceOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataReplaceOperation.java index 1cf15684587b..6e786520af57 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataReplaceOperation.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/patch/operation/DSpaceObjectMetadataReplaceOperation.java @@ -49,7 +49,8 @@ public R perform(Context context, R resource, Operation operation) throws SQLExc String[] partsOfPath = operation.getPath().split("/"); // Index of md being patched String indexInPath = (partsOfPath.length > 3) ? partsOfPath[3] : null; - MetadataValueRest metadataValueToReplace = metadataPatchUtils.extractMetadataValueFromOperation(operation); + List metadataValueToReplace = + metadataPatchUtils.extractMetadataValueListFromOperation(operation); // Property of md being altered String propertyOfMd = metadataPatchUtils.extractPropertyOfMdFromPath(partsOfPath); String newValueMdAttribute = metadataPatchUtils.extractNewValueOfMd(operation); @@ -78,6 +79,29 @@ public R perform(Context context, R resource, Operation operation) throws SQLExc */ private void replace(Context context, DSpaceObject dso, DSpaceObjectService dsoService, MetadataField metadataField, MetadataValueRest metadataValue, String index, String propertyOfMd, String valueMdProperty) { + replace(context, dso, dsoService, metadataField, List.of(metadataValue), index, propertyOfMd, valueMdProperty); + } + + /** + * Replaces metadata in the dso; 4 cases: + * * - If we replace everything: clears all metadata + * * - If we replace for a single field: clearMetadata on the field & add the new ones + * * - A single existing metadata value: + * * Retrieve the metadatavalue object & make alterations directly on this object + * * - A single existing metadata property: + * * Retrieve the metadatavalue object & make alterations directly on this object + * @param context context patch is being performed in + * @param dso dso being patched + * @param dsoService service doing the patch in db + * @param metadataField possible md field being patched (if null all md gets cleared) + * @param metadataValue list of values of md element + * @param index possible index of md being replaced + * @param propertyOfMd possible property of md being replaced + * @param valueMdProperty possible new value of property of md being replaced + */ + private void replace(Context context, DSpaceObject dso, DSpaceObjectService dsoService, MetadataField metadataField, + List metadataValue, String index, String propertyOfMd, + String valueMdProperty) { // replace entire set of metadata if (metadataField == null) { this.replaceAllMetadata(context, dso, dsoService); @@ -90,8 +114,8 @@ private void replace(Context context, DSpaceObject dso, DSpaceObjectService dsoS return; } // replace single existing metadata value - if (propertyOfMd == null) { - this.replaceSingleMetadataValue(dso, dsoService, metadataField, metadataValue, index); + if (propertyOfMd == null && !metadataValue.isEmpty()) { + this.replaceSingleMetadataValue(dso, dsoService, metadataField, metadataValue.get(0), index); return; } // replace single property of exiting metadata value @@ -119,16 +143,18 @@ private void replaceAllMetadata(Context context, DSpaceObject dso, DSpaceObjectS * @param dso dso being patched * @param dsoService service doing the patch in db * @param metadataField md field being patched - * @param metadataValue value of md element + * @param metadataValueList value of md element */ private void replaceMetadataFieldMetadata(Context context, DSpaceObject dso, DSpaceObjectService dsoService, - MetadataField metadataField, MetadataValueRest metadataValue) { + MetadataField metadataField, List metadataValueList) { try { dsoService.clearMetadata(context, dso, metadataField.getMetadataSchema().getName(), metadataField.getElement(), metadataField.getQualifier(), Item.ANY); - dsoService.addAndShiftRightMetadata(context, dso, metadataField.getMetadataSchema().getName(), + for (MetadataValueRest metadataValue : metadataValueList) { + dsoService.addAndShiftRightMetadata(context, dso, metadataField.getMetadataSchema().getName(), metadataField.getElement(), metadataField.getQualifier(), metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), metadataValue.getConfidence(), -1); + } } catch (SQLException e) { throw new DSpaceBadRequestException("SQLException in DspaceObjectMetadataOperation.replace trying to " + "remove and replace metadata from dso.", e);