DATAREST-837 - DomainObjectMerger doesn't nullify read-only properties on PUT.
PUT requests are supposed to replace the state of the resource with the request payload. However, Spring Data REST already handles a couple of domain object propoerties in a special way as theri values map to dedicated HTTP features: identifiers (URIs), last-modified dates (header) etc. For users, it might be worthwhile to exclude other properties from being set by applying the payload, like properties that are completely under the control of the server, e.g. creation user and date, last modifying user etc. So far, users didn't have any means to exclude those properties as the handling of PUT requests treated every missing property of the payload as null value. DomainObjectMerger now checks whether a property is actually writable before applying the implicit null value. The application can be disabled by annotation a property with @ReadOnlyProperty.
This commit is contained in:
@@ -121,7 +121,7 @@ public class DomainObjectReader {
|
||||
@Override
|
||||
public void doWithPersistentProperty(PersistentProperty<?> property) {
|
||||
|
||||
if (property.isIdProperty() || property.isVersionProperty()) {
|
||||
if (property.isIdProperty() || property.isVersionProperty() || !property.isWritable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -27,7 +28,9 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -61,6 +64,7 @@ public class DomainObjectReaderUnitTests {
|
||||
mappingContext.getPersistentEntity(Person.class);
|
||||
mappingContext.getPersistentEntity(TypeWithGenericMap.class);
|
||||
mappingContext.getPersistentEntity(VersionedType.class);
|
||||
mappingContext.getPersistentEntity(SampleWithCreatedDate.class);
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
PersistentEntities entities = new PersistentEntities(Collections.singleton(mappingContext));
|
||||
@@ -169,6 +173,23 @@ public class DomainObjectReaderUnitTests {
|
||||
assertThat(result.version, is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-873
|
||||
*/
|
||||
@Test
|
||||
public void doesNotApplyInputToReadOnlyFields() throws Exception {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ObjectNode node = (ObjectNode) mapper.readTree("{}");
|
||||
|
||||
Date reference = new Date();
|
||||
|
||||
SampleWithCreatedDate sample = new SampleWithCreatedDate();
|
||||
sample.createdDate = reference;
|
||||
|
||||
assertThat(reader.readPut(node, sample, mapper).createdDate, is(reference));
|
||||
}
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
|
||||
static class SampleUser {
|
||||
|
||||
@@ -210,4 +231,12 @@ public class DomainObjectReaderUnitTests {
|
||||
|
||||
String firstname, lastname;
|
||||
}
|
||||
|
||||
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
|
||||
static class SampleWithCreatedDate {
|
||||
|
||||
@CreatedDate //
|
||||
@ReadOnlyProperty //
|
||||
Date createdDate;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user