9

I'd like to read a JSON "tree" from a java byte array and write a JSON "tree" back out as java byte array using Jackson. One way to do it is shown below:

ObjectMapper om = new ObjectMapper();
JsonNode old = om.createObjectNode();

byte[] arr = om.writeValueAsBytes(old);
JsonNode new = om.readTree(arr);

However, Jackson these days recommends the use of ObjectReader and ObjectWriter instead of ObjectMapper, because of thread safety in configuration, but also because of optimizations that might be relevant for them only. But, ObjectReader does not support readTree with byte arrays directly, and writeValueAsBytes is more generic than writeTree so there might be a way (and a reason) to skip the type mapping logic somehow.

So, today, with the most recent Jackson (2.5), what is the fastest/best/recommended way to do these two conversions?

jww
  • 97,681
  • 90
  • 411
  • 885
Nakedible
  • 4,067
  • 7
  • 34
  • 40

1 Answers1

12

The problem with using the ObjectMapper directly is that if you alter the configuration of the mapper it can lead to problems. However, if you do not change the underlying config you should be safe anyway (more reading here).

But if you use the ObjectReader and ObjectWriter you are totally safe, even if you actually do alter the configuration of the mapper. This is possible since the reader/writer are immutable and it is therefore not possible to change the underlying state.

So, to read/write to bytes the following approach works fine:

ObjectMapper om = new ObjectMapper();
JsonNode oldNode = om.createObjectNode();

// Writing...
// Create an immutable writer (in this case using the default settings)
final ObjectWriter writer = om.writer();

// Use the writer for thread safe access.
final byte[] bytes = writer.writeValueAsBytes(oldNode);


// Reading...
// Create an immutable reader
final ObjectReader reader = om.reader();

// Use the reader for thread safe access
final JsonNode newNode = reader.readTree(new ByteArrayInputStream(bytes));

So, basically you can use the same principles (with the byte streams) but if you need to be sure that you are using thread safe access to the mapper you should access the reading/writing via the ObjectReader and ObjectWriter.

The writeValueAsBytes is described like this in the JavaDoc:

Functionally equivalent to calling writeValue(Writer,Object) with java.io.ByteArrayOutputStream and getting bytes, but more efficient.

For the reading you can simply use the readTree(InputStream) version.

Community
  • 1
  • 1
wassgren
  • 18,651
  • 6
  • 63
  • 77
  • Can you testify that using ByteArrayInputStream is as efficient as readTree with byte[]? For them to be, JsonFactory.createParser(byte[]) must be as efficient as JsonFactory.createParser(InputStream) and I doubt it is - but I might be wrong. – Nakedible Feb 02 '15 at 17:58
  • 1
    @Nakedible, I can easily say that I will never testify in such a matter ;) However, I did some simple [performance benchmarks](http://hastebin.com/eberuputon.avrasm) where I compared the different methods and the output can be [found here](http://hastebin.com/iyiseripol.profile). – wassgren Feb 03 '15 at 19:23
  • 1
    Okay, you convinced me, even though microbenchmarks always lie ;) Thank you, great answer! – Nakedible Feb 08 '15 at 18:53