14

I have a Java class with an Optional field. I am serializing the class to JSON using Jackson 2.8.3 (called from Spring web 4.3.3).

I am hoping to get the serializer to skip the field if the Optional is empty, and serialize the contained string if it is present. An example of the result I'm looking for with a list of two objects:

[
    {
        "id": 1,
        "foo": "bar"
    },
    {
        "id": 2,
    }
]

Here the foo Optional is empty for the object with id 2.

Instead, what I get is:

[
    {
        "id": 1,
        "foo": {
            "present": true
        }
    },
    {
        "id": 2,
        "foo": {
            "present": false
        }
    }
]

This is the result even if I annotate the "bar" field in the class like

@JsonInclude(JsonInclude.Include.NON_ABSENT)
public Optional<String> getFoo() { ...

Is there any way I can achieve a result like the first list using the Jackson annotations or a custom serializer?

3
  • 1
    As an aside, using Optional as a field of a bean is a Bad Idea™ in general. Commented Nov 3, 2016 at 19:05
  • Why is that considered problematic? Commented Nov 3, 2016 at 20:18
  • 1
    It wasn't designed for that kind of use. It's a very subtle semantic difference but in the case of a field, null is considered just another value. While if you're designing a method in the API of a library, you might want to emphasise that it may not return a value, and thus use Optional. See more here Commented Nov 3, 2016 at 20:55

3 Answers 3

34

No need to write custom serializer. Annotate your class with @JsonInclude(JsonInclude.Include.NON_ABSENT).

You also need to:

  • include com.fasterxml.jackson.datatype:jackson-datatype-jdk8 as your dependency
  • and to register the corresponding module with your object mapper: objectMapper.registerModule(new Jdk8Module());
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, including the dependency on com.fasterxml.jackson.datatype:jackson-datatype-jdk8 did the trick.
@JsonInclude(JsonInclude.Include.NON_ABSENT) will be good enough.
To exclude Optional.empty() fields, as the OP originally asked, one MUST add the depencandy and MUST set NON_ABSENT. NON_NULL is not enough.
4

You can use objectMapper.registerModule(new Jdk8Module()); but it serializes with null values.

But still you want to remove null values also from JSON, please use the following code:

objectMapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(true));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Comments

1

Use a JsonSerializer to your needs.

Something like this (semi-pseudo):

public class MySer extends JsonSerializer<Opional<?>> {

        @Override
        public void serialize(Optional<?> optString, JsonGenerator generator, SerializerProvider provider)
                                          throws IOException, JsonProcessingException {
        //Check Optional here...        
        generator.writeString(/* DO SOMETHING HERE WHATEVER */);
    }

//Then in your model:

public class ClassWhatever {           
    @JsonSerialize(using = MySer .class)
    public Optional<String> getFoo() { ...
 }

To avoid annotating every field with @JsonSerialize you may register your custom serializer to object mapper using

  ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new MyCustomSerializer()); // assuming serializer declares correct class to bind to
mapper.registerModule(testModule);

Also, given solution works only for serialization. Deserialization will fail unless you write your own deserializer. Then you need to annotate every field with @JsonDeserialize or register your custom deserializer.

2 Comments

com.fasterxml.jackson.datatype:jackson-datatype-jdk8 is better option. with such custom solution you need to annotate every field. Also, deserialization will not work unless -you write custom deserializer and annotate every field with @JsonDeserialize
@BartoszBilicki Certainly, in agreement with you there. Both would work, but your recommendation is better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.