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:
@@ -216,7 +216,7 @@ public class DomainObjectReader {
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = candidate.get();
|
||||
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);
|
||||
|
||||
@@ -226,7 +226,7 @@ public class JacksonMappingAwareSortTranslator {
|
||||
this.objectMapper = objectMapper;
|
||||
this.currentType = persistentEntity;
|
||||
this.currentProperties = persistentEntity//
|
||||
.map(it -> MappedProperties.fromJacksonProperties(it, objectMapper))//
|
||||
.map(it -> MappedProperties.forSerialization(it, objectMapper))//
|
||||
.orElseGet(() -> MappedProperties.none());
|
||||
this.currentWrappedProperties = persistentEntity//
|
||||
.map(it -> WrappedProperties.fromJacksonProperties(persistentEntities, it, objectMapper))//
|
||||
|
||||
@@ -32,7 +32,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;
|
||||
@@ -89,16 +91,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);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,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;
|
||||
@@ -202,8 +203,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 Optional<AnnotatedMember> findAnnotatedMember(BeanPropertyDefinition property) {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class MappedPropertiesUnitTests {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
KeyValueMappingContext<?, ?> context = new KeyValueMappingContext<>();
|
||||
PersistentEntity<?, ?> entity = context.getRequiredPersistentEntity(Sample.class);
|
||||
MappedProperties properties = MappedProperties.fromJacksonProperties(entity, mapper);
|
||||
MappedProperties properties = MappedProperties.forDeserialization(entity, mapper);
|
||||
|
||||
@Test // DATAREST-575
|
||||
public void doesNotExposeMappedPropertyForNonSpringDataPersistentProperty() {
|
||||
@@ -75,6 +75,15 @@ public class MappedPropertiesUnitTests {
|
||||
assertThat(properties.getPersistentProperty("readOnlyProperty")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-1248
|
||||
public void doesNotExcludeReadOnlyPropertiesForSerialization() {
|
||||
|
||||
MappedProperties properties = MappedProperties.forSerialization(entity, mapper);
|
||||
|
||||
assertThat(properties.hasPersistentPropertyForField("readOnlyProperty")).isTrue();
|
||||
assertThat(properties.getPersistentProperty("readOnlyProperty")).isNotNull();
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
public @Transient String notExposedBySpringData;
|
||||
|
||||
@@ -34,6 +34,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;
|
||||
|
||||
@@ -171,12 +172,22 @@ public class SortTranslatorUnitTests {
|
||||
assertThat(translatedSort.getOrderFor("burrito.embedded.name")).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAREST-1248
|
||||
public void allowsSortingByReadOnlyProperty() {
|
||||
|
||||
Sort sort = sortTranslator.translateSort(Sort.by("readOnly"),
|
||||
mappingContext.getRequiredPersistentEntity(Plain.class));
|
||||
|
||||
assertThat(sort.getOrderFor("readOnly")).isNotNull();
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user