DATAREST-1248 - SortTranslator now considers read-only properties sortable.

MappedProperties now exposes a factory method that uses the Jackson introspector for serialization (instead of deserialization) which now also includes read-only properties. Previously, read-only ones were not considered as they are excluded from the metadata if it is looked up for deserialization.
This commit is contained in:
Oliver Gierke
2018-08-07 16:05:57 +02:00
parent 8e7665ce6a
commit 8c2aecce6c
6 changed files with 53 additions and 10 deletions

View File

@@ -219,7 +219,7 @@ public class DomainObjectReader {
return mapper.readerForUpdating(target).readValue(root);
}
MappedProperties mappedProperties = MappedProperties.fromJacksonProperties(entity, mapper);
MappedProperties mappedProperties = MappedProperties.forDeserialization(entity, mapper);
for (Iterator<Entry<String, JsonNode>> i = root.fields(); i.hasNext();) {
@@ -616,7 +616,7 @@ public class DomainObjectReader {
Assert.notNull(entity, "PersistentEntity must not be null!");
Assert.notNull(mapper, "ObjectMapper must not be null!");
this.properties = MappedProperties.fromJacksonProperties(entity, mapper);
this.properties = MappedProperties.forDeserialization(entity, mapper);
this.targetAccessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(target),
new DefaultConversionService());
this.sourceAccessor = entity.getPropertyAccessor(source);

View File

@@ -226,7 +226,7 @@ public class JacksonMappingAwareSortTranslator {
if (persistentEntity != null) {
this.currentProperties = MappedProperties.fromJacksonProperties(currentType, objectMapper);
this.currentProperties = MappedProperties.forSerialization(currentType, objectMapper);
this.currentWrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, currentType,
objectMapper);

View File

@@ -28,7 +28,9 @@ import org.springframework.data.mapping.PersistentProperty;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.introspect.ClassIntrospector;
@@ -81,16 +83,34 @@ class MappedProperties {
}
/**
* Creates {@link MappedProperties} for the given {@link PersistentEntity}.
* Creates {@link MappedProperties} for the given {@link PersistentEntity} for deserialization purposes. Will not
* include Jackson-read-only properties.
*
* @param entity must not be {@literal null}.
* @param mapper must not be {@literal null}.
* @return
*/
public static MappedProperties fromJacksonProperties(PersistentEntity<?, ?> entity, ObjectMapper mapper) {
public static MappedProperties forDeserialization(PersistentEntity<?, ?> entity, ObjectMapper mapper) {
BeanDescription description = INTROSPECTOR.forDeserialization(mapper.getDeserializationConfig(),
mapper.constructType(entity.getType()), mapper.getDeserializationConfig());
DeserializationConfig config = mapper.getDeserializationConfig();
BeanDescription description = INTROSPECTOR.forDeserialization(config, mapper.constructType(entity.getType()),
config);
return new MappedProperties(entity, description);
}
/**
* Creates {@link MappedProperties} for the given {@link PersistentEntity} for serialization purposes. Includes
* Jackson-read-only properties.
*
* @param entity must not be {@literal null}.
* @param mapper must not be {@literal null}.
* @return
*/
public static MappedProperties forSerialization(PersistentEntity<?, ?> entity, ObjectMapper mapper) {
SerializationConfig config = mapper.getSerializationConfig();
BeanDescription description = INTROSPECTOR.forSerialization(config, mapper.constructType(entity.getType()), config);
return new MappedProperties(entity, description);
}

View File

@@ -34,6 +34,7 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
@@ -200,8 +201,10 @@ class WrappedProperties {
}
private BeanDescription getBeanDescription(Class<?> type) {
return INTROSPECTOR.forDeserialization(mapper.getDeserializationConfig(), mapper.constructType(type),
mapper.getDeserializationConfig());
SerializationConfig config = mapper.getSerializationConfig();
return INTROSPECTOR.forSerialization(config, mapper.constructType(type), config);
}
private static AnnotatedMember findAnnotatedMember(BeanPropertyDefinition property) {

View File

@@ -38,7 +38,7 @@ public class MappedPropertiesUnitTests {
ObjectMapper mapper = new ObjectMapper();
KeyValueMappingContext context = new KeyValueMappingContext();
KeyValuePersistentEntity<?> entity = context.getPersistentEntity(Sample.class);
MappedProperties properties = MappedProperties.fromJacksonProperties(entity, mapper);
MappedProperties properties = MappedProperties.forDeserialization(entity, mapper);
@Test // DATAREST-575
public void doesNotExposeMappedPropertyForNonSpringDataPersistentProperty() {
@@ -76,6 +76,15 @@ public class MappedPropertiesUnitTests {
assertThat(properties.getPersistentProperty("readOnlyProperty"), is(nullValue()));
}
@Test // DATAREST-1248
public void doesNotExcludeReadOnlyPropertiesForSerialization() {
MappedProperties properties = MappedProperties.forSerialization(entity, mapper);
assertThat(properties.hasPersistentPropertyForField("readOnlyProperty"), is(true));
assertThat(properties.getPersistentProperty("readOnlyProperty"), is(notNullValue()));
}
static class Sample {
public @Transient String notExposedBySpringData;

View File

@@ -35,6 +35,7 @@ import org.springframework.data.rest.webmvc.json.JacksonMappingAwareSortTranslat
import org.springframework.data.rest.webmvc.mapping.Associations;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -172,12 +173,22 @@ public class SortTranslatorUnitTests {
assertThat(translatedSort.getOrderFor("burrito.embedded.name"), is(notNullValue()));
}
@Test // DATAREST-1248
public void allowsSortingByReadOnlyProperty() {
Sort sort = sortTranslator.translateSort(new Sort("readOnly"), mappingContext.getPersistentEntity(Plain.class));
assertThat(sort, is(notNullValue()));
assertThat(sort.getOrderFor("readOnly"), is(notNullValue()));
}
static class Plain {
public String name;
public Embedded embedded;
@Reference public Embedded refEmbedded;
@Reference public AnotherRootEntity association;
@JsonProperty(access = Access.READ_ONLY) public String readOnly;
}
static class UnwrapEmbedded {