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.
This commit is contained in:
Oliver Gierke
2016-04-01 11:31:10 +02:00
parent ccdeae7bbd
commit 47e89d9fec
2 changed files with 18 additions and 14 deletions

View File

@@ -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));

View File

@@ -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();
}