user3335313
user3335313

Reputation: 55

Jackson Mapper serialize empty object instead of null

Say I have classes Foo

public class Foo {
    private Bar bar;
}

and Bar

public class Bar {
    private String fizz;
    private String bang;
}

EDIT: For clarification I do not own Foo and Bar and cannot alter these classes.

If I want to serialize an empty object of type Foo, it's member, which is of type Bar, will be returned as null.

String json = objectMapper.writeValueAsString(new Foo()); // "{"bar" : null}"

Is there any way I can get the object mapper to serialize an empty Bar object without having to instantiate a new instance of Bar and then adding it to a new instance of Foo?

String json = objectMapper.writeValueAsString(new Foo()) // "{bar": {"fizz" : null, "bang" : null } }"

Upvotes: 4

Views: 18403

Answers (5)

Ferdynand Kiepski
Ferdynand Kiepski

Reputation: 331

If you don't want to write your own serializer you can use this approach of declaring type of field as ObjectNode:

private ObjectNode data;

You can set/initialize it like this:

data = new ObjectNode(JsonNodeFactory.instance)

Upvotes: 2

SKO
SKO

Reputation: 50

It's a bit unrelated to this, but if you define members as private on data class in Kotlin, then, Jackson serializer will produce empty json such as {}.

Upvotes: 0

Cmyker
Cmyker

Reputation: 2568

I was also required to produce such a structure for legacy client compatibility, here is my solution (depends on Spring Boot since uses @JsonComponent annotation)

Create "special object" that will be treated as empty

public class EmptyObject {
}

Create property in your model

@JsonProperty("data")
private EmptyObject data = new EmptyObject();

public EmptyObject getData() {
    return data;
}

Create serializer that will process empty object above

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.sevensenders.datahub.api.service.response.model.EmptyObject;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;

@JsonComponent
public class EmptyObjectSerializer extends StdSerializer<EmptyObject> {

    public EmptyObjectSerializer() {
        this(null);
    }

    public EmptyObjectSerializer(Class<EmptyObject> t) {
        super(t);
    }

    @Override
    public void serialize(EmptyObject value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // to maintain AF compatible format it is required to write {} instead of null
        gen.writeStartObject();
        gen.writeEndObject();
    }
}

Output:

{
  ...
  "data": {}
}

Upvotes: 9

eshayne
eshayne

Reputation: 935

You could create a custom serializer for serializing Foo objects. Then in your custom FooSerializer implementation, you could check for a null bar value and serialize it as a default Bar instance. See https://spin.atomicobject.com/2016/07/01/custom-serializer-jackson/ or http://www.baeldung.com/jackson-custom-serialization for some examples of how to create custom serializers.

Upvotes: 1

user7207455
user7207455

Reputation:

No. I don't see any way doing this. If you don't initialize your Bar, it'll be null inside the JSON.

Since you can't alter these classes, you can just check if the Bar inside the Foo is null and if it is, just initialize it and you'll get what you want.

Bar bar = foo.getBar();
if (bar == null) {
    foo.setBar(new Bar());
}
String json = objectMapper.writeValueAsString(foo);

The json will be the following:

{
    "bar" : {
        "fizz" : null, 
        "bang" : null 
    } 
}

Hope this helps.

Upvotes: -2

Related Questions