Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialization of root primitive objects with Jackson

I am facing the following problems. When Jackson serializer is passed a wrapped primitive for serialization, this primitive is serialized as is, for example:

objectMapper = new ObjectMapper();

StringWriter w = new StringWriter();
objectMapper.writeValue(w, Integer.valueOf(10));
System.out.println(w.toString());

produces 10 as output. However 10 is not a valid JSON (according to jsonlint) and should be wrapped either in square brackets ([10], so it will be a single-element array) or in curly brackets ({value:10}, so it will be an object with dummy property). The problem affects numbers, java.lang.String, java.util.Date, ...

My question is: How to make Jackson to perform the wrapping? Shouldn't Jackson always produce a valid JSON?

I have analyzed Jackson behavior with SerializationConfig.Feature.WRAP_ROOT_VALUE enabled: it does not work as I expect. Primitives are now serialized to valid JSON ({"Integer":10}), but "normal" Java beans are also wrapped which is undesired ({"MyBean":{"field":value, ...}} instead of {"field":value, ...}).

If somebody can advise how to customize Jackson, perhaps with custom serializer. The difficulty would be that it is necessary to distinguish the root primitive wrapper (which needs to be wrapped) from bean primitive property (does not need to be wrapped).

To make the story complete: Jackson serializer is used as message convertor for Spring MVC, and I doubt it is fairly easy to write a hook to intercept serialization of primitives (which will not call Jackson but will simply return "[" + String.toString(obj) + "]" when necessary). So I would prefer the solution with tuned Jackson.

like image 327
dma_k Avatar asked Jul 19 '12 15:07

dma_k


People also ask

How do I serialize an object graph in Jackson?

2. Standard Serialization of an Object Graph Let's define 2 simple entities and see how Jackson serializes these without any custom logic: Now, let's serialize an Item entity with a User entity: This will result in a full JSON representation for both entities: 3. Custom Serializer on the ObjectMapper

What are @JSONserialization annotations in Jackson?

Serialization annotations are used when we serialize Java objects into a Json string. Jackson library provides several serialization annotations such as @JsonSerialize, @JacksonGetter, @JsonAnyGetter, etc. Let's understand each one of them one by one with an example.

How to serialize a Java object to JSON?

Also, on the writing side, we can use the writeValue API to serialize any Java object as JSON output. We'll use the following Car class with two fields as the object to serialize or deserialize throughout this article: 3.1. Java Object to JSON

How do I read and write JSON in the Jackson Library?

The main class in the Jackson library for reading and writing JSON is ObjectMapper. It's in the com.fasterxml.jackson.databind package and can serialize and deserialize two types of objects: If you already have a domain class, a POJO, you can convert between that class and JSON by providing the class to the ObjectMapper.


1 Answers

Finally the custom serializer

import java.io.IOException;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.ser.std.ScalarSerializerBase;

public class NumberSerializer extends ScalarSerializerBase<Number> {

    protected NumberSerializer() {
        super(Number.class);
    }

    @Override
    public void serialize(Number value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
        if (jgen.getOutputContext().inRoot()) {
            jgen.writeStartArray();
            jgen.writeNumber(value.longValue());
            jgen.writeEndArray();
        }
        else {
            jgen.writeNumber(value.longValue());
        }
    }
}

did a job for me. Serializer can be registered as module (see here).

Note when using this seriazlier: As it turns all primitive into primitive arrays with only one element, is breaks the reflection principle in a sense that A != desrialize(serialize(A)) where A is some primitive.

like image 199
dma_k Avatar answered Oct 30 '22 06:10

dma_k