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:
@@ -219,7 +219,7 @@ public class DomainObjectReader {
|
|||||||
return mapper.readerForUpdating(target).readValue(root);
|
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();) {
|
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(entity, "PersistentEntity must not be null!");
|
||||||
Assert.notNull(mapper, "ObjectMapper 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),
|
this.targetAccessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(target),
|
||||||
new DefaultConversionService());
|
new DefaultConversionService());
|
||||||
this.sourceAccessor = entity.getPropertyAccessor(source);
|
this.sourceAccessor = entity.getPropertyAccessor(source);
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ public class JacksonMappingAwareSortTranslator {
|
|||||||
|
|
||||||
if (persistentEntity != null) {
|
if (persistentEntity != null) {
|
||||||
|
|
||||||
this.currentProperties = MappedProperties.fromJacksonProperties(currentType, objectMapper);
|
this.currentProperties = MappedProperties.forSerialization(currentType, objectMapper);
|
||||||
this.currentWrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, currentType,
|
this.currentWrappedProperties = WrappedProperties.fromJacksonProperties(persistentEntities, currentType,
|
||||||
objectMapper);
|
objectMapper);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import org.springframework.data.mapping.PersistentProperty;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.BeanDescription;
|
import com.fasterxml.jackson.databind.BeanDescription;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationConfig;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.BasicClassIntrospector;
|
||||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||||
import com.fasterxml.jackson.databind.introspect.ClassIntrospector;
|
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 entity must not be {@literal null}.
|
||||||
* @param mapper must not be {@literal null}.
|
* @param mapper must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static MappedProperties fromJacksonProperties(PersistentEntity<?, ?> entity, ObjectMapper mapper) {
|
public static MappedProperties forDeserialization(PersistentEntity<?, ?> entity, ObjectMapper mapper) {
|
||||||
|
|
||||||
BeanDescription description = INTROSPECTOR.forDeserialization(mapper.getDeserializationConfig(),
|
DeserializationConfig config = mapper.getDeserializationConfig();
|
||||||
mapper.constructType(entity.getType()), 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);
|
return new MappedProperties(entity, description);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
|||||||
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
||||||
import com.fasterxml.jackson.databind.BeanDescription;
|
import com.fasterxml.jackson.databind.BeanDescription;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
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.AnnotatedMember;
|
||||||
import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector;
|
import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector;
|
||||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||||
@@ -200,8 +201,10 @@ class WrappedProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BeanDescription getBeanDescription(Class<?> type) {
|
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) {
|
private static AnnotatedMember findAnnotatedMember(BeanPropertyDefinition property) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class MappedPropertiesUnitTests {
|
|||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
KeyValueMappingContext context = new KeyValueMappingContext();
|
KeyValueMappingContext context = new KeyValueMappingContext();
|
||||||
KeyValuePersistentEntity<?> entity = context.getPersistentEntity(Sample.class);
|
KeyValuePersistentEntity<?> entity = context.getPersistentEntity(Sample.class);
|
||||||
MappedProperties properties = MappedProperties.fromJacksonProperties(entity, mapper);
|
MappedProperties properties = MappedProperties.forDeserialization(entity, mapper);
|
||||||
|
|
||||||
@Test // DATAREST-575
|
@Test // DATAREST-575
|
||||||
public void doesNotExposeMappedPropertyForNonSpringDataPersistentProperty() {
|
public void doesNotExposeMappedPropertyForNonSpringDataPersistentProperty() {
|
||||||
@@ -76,6 +76,15 @@ public class MappedPropertiesUnitTests {
|
|||||||
assertThat(properties.getPersistentProperty("readOnlyProperty"), is(nullValue()));
|
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 {
|
static class Sample {
|
||||||
|
|
||||||
public @Transient String notExposedBySpringData;
|
public @Transient String notExposedBySpringData;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.springframework.data.rest.webmvc.json.JacksonMappingAwareSortTranslat
|
|||||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty.Access;
|
||||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
@@ -172,12 +173,22 @@ public class SortTranslatorUnitTests {
|
|||||||
assertThat(translatedSort.getOrderFor("burrito.embedded.name"), is(notNullValue()));
|
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 {
|
static class Plain {
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
public Embedded embedded;
|
public Embedded embedded;
|
||||||
@Reference public Embedded refEmbedded;
|
@Reference public Embedded refEmbedded;
|
||||||
@Reference public AnotherRootEntity association;
|
@Reference public AnotherRootEntity association;
|
||||||
|
@JsonProperty(access = Access.READ_ONLY) public String readOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class UnwrapEmbedded {
|
static class UnwrapEmbedded {
|
||||||
|
|||||||
Reference in New Issue
Block a user