Best Handling for Jackson Json Reader?

Best Handling for Jackson Json Reader?

I'm wrapping the Jackson JSON processors in my own class and I haven't found a definitive thread-safe and performant way to handle sharing instances.

According to the docs, ObjectMapper, ObjectWriter and ObjectReader are all thread-safe and I should use ObjectWriter and ObjectReader preferentially.

Handling ObjectWriter is pretty straight-forward but there's no explicit instructions for ObjectReader even on Jackson Data-bind docs and it is hinting that I should create all my own ObjectReaders and cache them. So this is what I've done:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;

import java.util.HashMap;
import java.util.Map;

public class JacksonEngine extends JsonProcessor {

    private ObjectMapper mapper = new ObjectMapper();
    private ObjectWriter writer = mapper.writer();    
    private Map<Class, ObjectReader> readers = new HashMap<>();

    public String serialize(Object object) throws Exception {
        return writer.writeValueAsString(object);
    }

    public <T> T deserialize(String json, Class<T> classOfT)
            throws Exception {
        if (!readers.containsKey(classOfT)) {
            readers.put(classOfT, mapper.readerFor(classOfT));
        }
        return readers.get(classOfT).readValue(json);
    }

}

Is this going to work?

I assume all the generified Class<T> that must be reduced to non-generic Class for the hashmap key will be OK.

I also assume that the non-atomic if not present then add operation to put new Readers into the cache in multithreading conditions will not be an issue, except for the potential creation of a redundant reader or two.

Lastly I assume that it's worth doing the caching of Readers for sake of performance even though I haven't found any examples online of people doing so.

2 Answers

I think you don't actually need ObjectReader and ObjectWriter here. They are thread-safe and thus can be shared. As you don't share the reader and writer, you can keep it simple:

public class JacksonEngine extends JsonProcessor {

    private final static ObjectMapper mapper = new ObjectMapper();

    public String serialize(Object object) throws Exception {
        return mapper.writeValueAsString(object);
    }

    public <T> T deserialize(String json, Class<T> classOfT)
            throws Exception {
        return mapper.readValue(json, classOfT);
    }

}

UPDATE:

As OP is concerned about performance when calling ObjectMapper.readValue() as it creates everytime a new reader. A look at the source code shows that this is not the case:

public <T> T readValue(String content, Class<T> valueType) {
    return (T) _readMapAndClose(_jsonFactory.createParser(content), _typeFactory.constructType(valueType));
} 

protected Object _readMapAndClose(JsonParser p0, JavaType valueType) {
    try {
        Object result;
        // ...
        JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
        // ...
        result = deser.deserialize(p, ctxt);
        // ...
        return result;
    }
}
7

can be reused, shared, cached; both because of thread-safety and because instances are relatively light-weight.

ObjectReader javadoc

Your approach is incorrect regardless of whether ObjectReader is thread-safe. Firstly, your fields should be final; without final, if you share JacksonEngine across threads, it is possible for its state to not be fully initialized when it is read and will be seen in a corrupt state. Secondly, your assumption about "if not present then add" is also incorrect; even if you do not need atomicity, the use of a HashMap may not update for other threads, it may fail every call, you may not see it cached in the HashMap, etc. You're caching without effect.

Just store your ObjectReader in a constant and it should be fine, if that doesn't go, this would be a good place to use ThreadLocal.

3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

David Miller
Author

David Miller

David Miller brings 15 years of experience in global economics, personal finance strategy, and market dynamics. He specializes in turning complex economic trends into actionable insights for everyday readers.