From fe0d0090b6bcd07e921d642d745b5595c4cff0b7 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Tue, 19 Oct 2021 13:54:18 +0200 Subject: [PATCH] #1693 - Avoid serializing empty beans in EntityModel. The unwrapping nature of EntityModel.getContent() does not work well with value that would result in an empty object being rendered. We now skip the rendering if failing for empty beans is disabled. --- .../springframework/hateoas/EntityModel.java | 7 +++++++ .../hateoas/EntityModelIntegrationTest.java | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/main/java/org/springframework/hateoas/EntityModel.java b/src/main/java/org/springframework/hateoas/EntityModel.java index 4527a29c..6c0f9857 100644 --- a/src/main/java/org/springframework/hateoas/EntityModel.java +++ b/src/main/java/org/springframework/hateoas/EntityModel.java @@ -33,9 +33,11 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.fasterxml.jackson.databind.ser.impl.UnknownSerializer; import com.fasterxml.jackson.databind.ser.std.JsonValueSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.util.NameTransformer; @@ -235,6 +237,11 @@ public class EntityModel extends RepresentationModel> { JsonSerializer serializer = provider.findValueSerializer(value.getClass()); + if (UnknownSerializer.class.isInstance(serializer) + && !provider.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) { + return; + } + if (JsonValueSerializer.class.isInstance(serializer)) { throw new IllegalStateException( "@JsonValue rendered classes can not be directly nested in EntityModel as they do not produce a document key!"); diff --git a/src/test/java/org/springframework/hateoas/EntityModelIntegrationTest.java b/src/test/java/org/springframework/hateoas/EntityModelIntegrationTest.java index 41479ae6..8c094e7e 100755 --- a/src/test/java/org/springframework/hateoas/EntityModelIntegrationTest.java +++ b/src/test/java/org/springframework/hateoas/EntityModelIntegrationTest.java @@ -21,6 +21,9 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; /** * Integration tests for {@link EntityModel}. @@ -59,6 +62,22 @@ class EntityModelIntegrationTest extends AbstractJackson2MarshallingIntegrationT assertThat(result.getContent().lastname).isEqualTo("Matthews"); } + @Test // #1686 + void doesNotFailOnSerializingEmptyBean() { + + ObjectMapper mapper = MappingTestUtils.defaultObjectMapper(); + + // Fail if we're supposed to + assertThatExceptionOfType(JsonMappingException.class) // + .isThrownBy(() -> mapper.enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .writeValueAsString(EntityModel.of(new Empty()))); + + // Ignore empty bean if we're supposed to + assertThatNoException() // + .isThrownBy(() -> mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .writeValueAsString(EntityModel.of(new Empty()))); + } + static class PersonModel extends EntityModel { public PersonModel(Person person) { @@ -74,4 +93,6 @@ class EntityModelIntegrationTest extends AbstractJackson2MarshallingIntegrationT String firstname; String lastname; } + + static class Empty {} }