DATAREST-957 - Improved PUT handling for transient properties not backed by a field.
When copying the transient properties of an aggregate, we now try field based access first and fall back to accessor based copying in case both a setter and getter are exposed on the type. Previously we always expected a field to be present which doesn't necessarily has to be the case. Related ticket: DATAREST-986.
This commit is contained in:
@@ -204,11 +204,23 @@ public class DomainObjectReader {
|
||||
*/
|
||||
private static void copyRemainingProperties(MappedProperties properties, Object source, Object target) {
|
||||
|
||||
PropertyAccessor sourceAccessor = PropertyAccessorFactory.forDirectFieldAccess(source);
|
||||
PropertyAccessor targetAccessor = PropertyAccessorFactory.forDirectFieldAccess(target);
|
||||
PropertyAccessor sourceFieldAccessor = PropertyAccessorFactory.forDirectFieldAccess(source);
|
||||
PropertyAccessor sourcePropertyAccessor = PropertyAccessorFactory.forBeanPropertyAccess(source);
|
||||
PropertyAccessor targetFieldAccessor = PropertyAccessorFactory.forDirectFieldAccess(target);
|
||||
PropertyAccessor targetPropertyAccessor = PropertyAccessorFactory.forBeanPropertyAccess(target);
|
||||
|
||||
for (String property : properties.getSpringDataUnmappedProperties()) {
|
||||
targetAccessor.setPropertyValue(property, sourceAccessor.getPropertyValue(property));
|
||||
|
||||
// If there's a field we can just copy it.
|
||||
if (targetFieldAccessor.isWritableProperty(property)) {
|
||||
targetFieldAccessor.setPropertyValue(property, sourceFieldAccessor.getPropertyValue(property));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise only copy if there's both a getter and setter.
|
||||
if (targetPropertyAccessor.isWritableProperty(property) && sourcePropertyAccessor.isReadableProperty(property)) {
|
||||
targetPropertyAccessor.setPropertyValue(property, sourcePropertyAccessor.getPropertyValue(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ public class DomainObjectReaderUnitTests {
|
||||
mappingContext.getPersistentEntity(Outer.class);
|
||||
mappingContext.getPersistentEntity(Parent.class);
|
||||
mappingContext.getPersistentEntity(Product.class);
|
||||
mappingContext.getPersistentEntity(TransientReadOnlyProperty.class);
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
PersistentEntities entities = new PersistentEntities(Collections.singleton(mappingContext));
|
||||
@@ -441,6 +442,15 @@ public class DomainObjectReaderUnitTests {
|
||||
assertThat(result.map.get(Locale.GERMAN), is(new LocalizedValue("schlussendlich")));
|
||||
}
|
||||
|
||||
@Test // DATAREST-987
|
||||
public void handlesTransientPropertyWithoutFieldProperly() throws Exception {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode node = mapper.readTree("{ \"name\" : \"Foo\" }");
|
||||
|
||||
reader.readPut((ObjectNode) node, new TransientReadOnlyProperty(), mapper);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T as(Object source, Class<T> type) {
|
||||
|
||||
@@ -564,4 +574,15 @@ public class DomainObjectReaderUnitTests {
|
||||
static class LocalizedValue {
|
||||
String value;
|
||||
}
|
||||
|
||||
@JsonAutoDetect(getterVisibility = Visibility.ANY)
|
||||
static class TransientReadOnlyProperty {
|
||||
|
||||
@Transient
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setName(String name) {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user