Skip to content

Commit a66650a

Browse files
committed
Prevent using NestedEntitySerializer if target serializer does not support unwrapping.
We now verify that the serializer registered for the type that's supposed to be handled by the NestedEntitySerializer actually supports unwrapping as the serialization in EntityModel (MapSuppressingUnwrappingSerializer) requires that to work properly. Fixes #2056.
1 parent 7142e84 commit a66650a

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,12 @@ private Object toModel(Object value, SerializerProvider provider) throws JsonMap
405405
return value;
406406
}
407407

408+
JsonSerializer<Object> unwrappingSerializer = serializer.unwrappingSerializer(NameTransformer.NOP);
409+
410+
if (!unwrappingSerializer.isUnwrappingSerializer()) {
411+
return value;
412+
}
413+
408414
PersistentEntity<?, ?> entity = entities.getRequiredPersistentEntity(value.getClass());
409415

410416
return invoker.invokeProcessorsFor(PersistentEntityResource.build(value, entity).//

spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@
4646
import org.springframework.data.rest.core.support.EntityLookup;
4747
import org.springframework.data.rest.core.support.SelfLinkProvider;
4848
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
49+
import org.springframework.data.rest.webmvc.PersistentEntityResource;
4950
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.AssociationOmittingSerializerModifier;
5051
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.AssociationUriResolvingDeserializerModifier;
5152
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.LookupObjectSerializer;
5253
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
5354
import org.springframework.data.rest.webmvc.mapping.Associations;
5455
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
56+
import org.springframework.hateoas.EntityModel;
5557
import org.springframework.hateoas.UriTemplate;
5658
import org.springframework.hateoas.server.EntityLinks;
5759
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
@@ -62,8 +64,11 @@
6264
import com.fasterxml.jackson.annotation.JsonProperty;
6365
import com.fasterxml.jackson.annotation.JsonTypeInfo;
6466
import com.fasterxml.jackson.annotation.JsonValue;
67+
import com.fasterxml.jackson.core.JsonGenerator;
6568
import com.fasterxml.jackson.databind.ObjectMapper;
69+
import com.fasterxml.jackson.databind.SerializerProvider;
6670
import com.fasterxml.jackson.databind.module.SimpleModule;
71+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
6772
import com.jayway.jsonpath.JsonPath;
6873

6974
/**
@@ -95,19 +100,21 @@ void setUp() {
95100
mappingContext.getPersistentEntity(PersistentEntityJackson2ModuleUnitTests.PetOwner.class);
96101
mappingContext.getPersistentEntity(Immutable.class);
97102
mappingContext.getPersistentEntity(Wrapper.class);
103+
mappingContext.getPersistentEntity(Surrounding.class);
98104

99105
this.persistentEntities = new PersistentEntities(Arrays.asList(mappingContext));
100106

101107
RepresentationModelProcessorInvoker invoker = new RepresentationModelProcessorInvoker(Collections.emptyList());
102108

103109
NestedEntitySerializer nestedEntitySerializer = new NestedEntitySerializer(persistentEntities,
104110
new EmbeddedResourcesAssembler(persistentEntities, associations, mock(ExcerptProjector.class)), invoker);
105-
SimpleModule module = new SimpleModule();
106111

112+
SimpleModule module = new SimpleModule();
107113
module.setSerializerModifier(new AssociationOmittingSerializerModifier(persistentEntities, associations,
108114
nestedEntitySerializer, new LookupObjectSerializer(PluginRegistry.of(new HomeLookup()))));
109115
module.setDeserializerModifier(
110116
new AssociationUriResolvingDeserializerModifier(persistentEntities, associations, converter, factory));
117+
module.addSerializer(new CustomTypeSerializer());
111118

112119
this.mapper = new ObjectMapper();
113120
this.mapper.registerModule(module);
@@ -213,6 +220,14 @@ void doesNotWrapJsonValueTypesIntoEntityModel() throws Exception {
213220
assertThat(mapper.writeValueAsString(wrapper)).isEqualTo("{\"value\":\"sample\"}");
214221
}
215222

223+
@Test // GH-2056
224+
void doesNotWrapValuesWithoutUnwrappingSerializer() {
225+
226+
EntityModel<Surrounding> model = PersistentEntityResource.of(new Surrounding());
227+
228+
assertThatNoException().isThrownBy(() -> mapper.writeValueAsString(model));
229+
}
230+
216231
/**
217232
* @author Oliver Gierke
218233
*/
@@ -284,4 +299,35 @@ static class Wrapper {
284299
static class ValueType {
285300
@JsonValue String value;
286301
}
302+
303+
// GH-2056
304+
305+
@Data
306+
static class Surrounding {
307+
CustomType custom = new CustomType();
308+
}
309+
310+
static class CustomType {}
311+
312+
static class CustomTypeSerializer extends StdSerializer<CustomType> {
313+
314+
private static final long serialVersionUID = -3841651446883968079L;
315+
316+
public CustomTypeSerializer() {
317+
super(CustomType.class);
318+
}
319+
320+
/*
321+
* (non-Javadoc)
322+
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
323+
*/
324+
@Override
325+
public void serialize(CustomType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
326+
327+
gen.writeStartObject();
328+
gen.writeFieldName("foo");
329+
gen.writeString("bar");
330+
gen.writeEndObject();
331+
}
332+
}
287333
}

0 commit comments

Comments
 (0)