From 47e89d9fecaedcaaf8b630b20eb3c7d7c475ad3e Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 1 Apr 2016 11:31:10 +0200 Subject: [PATCH] DATAREST-792 - Fixed handling of PUT request with customized entity lookups. Until now, the controller handling a PUT request for an item resource defensively tried to set the identifier of the entity to update to guard against request payloads accidentally modifying the identifier of entities to be uploaded by using the raw identifier from the URI. Through the introduction of customized entity lookups this isn't necessarily the actual entity identifier anymore. We now apply this defensive logic in the argument resolver for the incoming PersistentEntityResource where we have access to the object to update, can lookup the actual identifier directly and set it back after Jackson has applied the request body to the object to update. Related tickets: DATAREST-724. --- .../webmvc/RepositoryEntityController.java | 14 ++------------ ...yResourceHandlerMethodArgumentResolver.java | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index 92029c3ac..c14af59c0 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -31,8 +31,6 @@ import org.springframework.core.convert.ConversionService; import org.springframework.data.auditing.AuditableBeanWrapperFactory; import org.springframework.data.domain.Sort; import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.PersistentPropertyAccessor; -import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.data.querydsl.binding.QuerydslPredicate; import org.springframework.data.repository.support.Repositories; import org.springframework.data.repository.support.RepositoryInvoker; @@ -387,17 +385,9 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem resourceInformation.verifySupportedMethod(HttpMethod.PUT, ResourceType.ITEM); - // Force ID on unmarshalled object - PersistentPropertyAccessor incomingWrapper = new ConvertingPropertyAccessor(payload.getPropertyAccessor(), - conversionService); - incomingWrapper.setProperty(payload.getPersistentEntity().getIdProperty(), id); - RepositoryInvoker invoker = resourceInformation.getInvoker(); - Object objectToSave = incomingWrapper.getBean(); - - Object domainObject = payload.getContent(); - - eTag.verify(resourceInformation.getPersistentEntity(), domainObject); + Object objectToSave = payload.getContent(); + eTag.verify(resourceInformation.getPersistentEntity(), objectToSave); return payload.isNew() ? createAndReturn(objectToSave, invoker, assembler, config.returnBodyOnCreate(acceptHeader)) : saveAndReturn(objectToSave, invoker, PUT, assembler, config.returnBodyOnUpdate(acceptHeader)); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceHandlerMethodArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceHandlerMethodArgumentResolver.java index a953392cc..95cb95779 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceHandlerMethodArgumentResolver.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceHandlerMethodArgumentResolver.java @@ -22,6 +22,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import org.springframework.core.MethodParameter; +import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.repository.support.RepositoryInvoker; import org.springframework.data.rest.webmvc.IncomingRequest; import org.springframework.data.rest.webmvc.PersistentEntityResource; @@ -124,14 +125,27 @@ public class PersistentEntityResourceHandlerMethodArgumentResolver implements Ha Serializable id = idResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); Object objectToUpdate = getObjectToUpdate(id, resourceInformation); - boolean forUpdate = objectToUpdate != null; + + boolean forUpdate = false; + Object entityIdentifier = null; + PersistentEntity entity = resourceInformation.getPersistentEntity(); + + if (objectToUpdate != null) { + forUpdate = true; + entityIdentifier = entity.getIdentifierAccessor(objectToUpdate).getIdentifier(); + } + Object obj = read(resourceInformation, incoming, converter, objectToUpdate); if (obj == null) { throw new HttpMessageNotReadableException(String.format(ERROR_MESSAGE, domainType)); } - Builder build = PersistentEntityResource.build(obj, resourceInformation.getPersistentEntity()); + if (entityIdentifier != null) { + entity.getPropertyAccessor(obj).setProperty(entity.getIdProperty(), entityIdentifier); + } + + Builder build = PersistentEntityResource.build(obj, entity); return forUpdate ? build.build() : build.forCreation(); }