Skip to content

@JsonInclude(NON_EMPTY) not honored when serializing Resource #748

@crombach

Description

@crombach

I am using Spring HATEOAS 0.25.0.RELEASE along with Spring Data REST 3.0.11.RELEASE (via Spring Boot 2.0.6.RELEASE), and a component from Spring Data REST does not honor the Jackson settings for empty collections when the type contained in the collection is not a primitive or default type.

I have a domain class annotated with @JsonInclude(JsonInclude.Include.NON_EMPTY). Let's say this class is called ExampleObject and it has two fields: label, a String, and nestedObjects, a Collection of ExampleObjects.

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class ExampleObject {

  private String label;
  private Collection<ExampleObject> nestedObjects;

  public ExampleObject() {
    nestedObjects = new ArrayList<ExampleObject>();
  }
 
  // Getters and setters

}

A default Jackson ObjectMapper will omit fields for which the value is an empty collection or array in the JSON output when an ExampleObject is serialized (e.g., if I Accept application/json from one of my REST endpoints). See the below mock example, assuming I am retrieving an ExampleObject with an empty nestedObjects Collection.

{
  "label" : "Example Object"
}

However, the combination of Spring HATEOAS and Spring Data REST does not seem to honor either of the above Jackson configuration methods. If I Accept application/hal+json, empty arrays and collections are always serialized as "[ ]". See the below mock example, which uses the same ExampleObject as above (wrapped in a Resource).

{
  "label" : "Example Object",
  "nestedObjects" : [ ],
  "_links" : {
    "ex:example" : {
      "href" : "http://localhost:8080/example"
    },
    "self" : {
      "href" : "http://localhost:8080"
    },
    "curies" : [ {
      "href" : "http://example.com/{rel}",
      "name" : "ex",
      "templated" : true
    } ]
  }
}

I'd expect to see something more like this (note the omitted "nestedObjects" field):

{
  "label" : "Example Object",
  "_links" : {
    "ex:example" : {
      "href" : "http://localhost:8080/example"
    },
    "self" : {
      "href" : "http://localhost:8080"
    },
    "curies" : [ {
      "href" : "http://example.com/{rel}",
      "name" : "ex",
      "templated" : true
    } ]
  }
}

I believe this behavior is possibly related to NestedEntitySerializer, which is defined in PersistentEntityJackson2Module.

NestedEntitySerializer extends com.fasterxml.jackson.databind.JsonSerializer, which has a method called isEmpty(SerializerProvider provider, T value). The default implementation simply checks if value is null.

NestedEntitySerializer#isEmpty(SerializerProvider provider, T value) is being called by com.fasterxml.jackson.databind.ser.BeanPropertyWriter#serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) when serializing a Resource.

A potential way to properly honor the @JsonInclude(NON_EMPTY) annotation and the WRITE_EMPTY_JSON_ARRAYS serialization feature is for NestedEntitySerializer to override the default implementation of isEmpty(SerializerProvider provider, T value) and check for empty collections, arrays, maps, and strings in addition to null values.

However, the real problem may be that NestedEntitySerializer is being used in the first place and another Serializer should be used instead in this case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions