Deep Copy using Jackson: String or JsonNode
Asked Answered
F

2

15

Objective: deep copy (or clone) of a Java object
One of the suggested ways (almost everywhere) to do it is using Jackson:

MyPojo myPojo = new MyPojo();
ObjectMapper mapper = new ObjectMapper();
MyPojo newPojo = mapper.readValue(mapper.writeValueAsString(myPojo), MyPojo.class);

Question: is the following better? in terms of performance? is there any drawbacks?

MyPojo myPojo = new MyPojo();
ObjectMapper mapper = new ObjectMapper();
MyPojo newPojo = mapper.treeToValue(mapper.valueToTree(myPojo), MyPojo.class);
Fryer answered 18/4, 2018 at 15:43 Comment(0)
F
22

Answered by Tatu Saloranta:

Second way should be bit more efficient since it only creates and uses logical token stream but does not have to encode JSON and then decode (parse) it to/from token stream. So that is close to optimal regarding Jackson.

About the only thing to make it even more optimal would be to directly use TokenBuffer (which is what Jackson itself uses for buffering). Something like:

TokenBuffer tb = new TokenBuffer(); // or one of factory methods
mapper.writeValue(tb, myPojo);
MyPojo copy = mapper.readValue(tb.asParser(), MyPojo.class);

This would further eliminate construction and traversal of the tree model. I don't know how big a difference it'll make, but is not much more code.

Thanks Tatu :)

Fryer answered 23/4, 2018 at 9:3 Comment(7)
That's Jackson's author, the best reference you can have. By the way, where did you get the answer? :)Heighttopaper
How did you build the TokenBuffer? It takes different arguments and I am unsure of what to use in a general purpose cloning function.Squish
@Squish it's a good question. I couldn't find the answer. (I didn't use the code, we ended up with different approach.)Fryer
I just had a quick go with this, and it seems it's actually slightly faster than Kryo.copy (In my usecase anyway. And well, it doesn't do the same thing. Still.). I'm baffled.Blum
The TokenBuffer can be created with TokenBuffer tb = new TokenBuffer(objectMapper, false);Southsouthwest
groups.google.com/g/jackson-user/c/NcHEhk1ODSc?pli=1 has this answerBaird
Yep, that’s me 😄Fryer
I
0

I have copied my "valueNode" during iteration and made a copy of it using ObjectMapper now "copyJsonNode" is the replica of "valueNode" which i need for further implementation.

  if (entry.getKey().equalsIgnoreCase("admin")) {

                JsonNode valueNode = entry.getValue();
                
                String copyjson = valueNode.toString();

                ObjectMapper objectMapper = new ObjectMapper();

                JsonNode copyJsonNode = objectMapper.readTree(copyjson);

               ....}
Illusive answered 4/8, 2022 at 9:12 Comment(2)
Isn't this going to be far slower than just doing JsonNode copyJsonNode = valueNode.deepCopy() ?? Seems like parsing a string to JSON would take longer than copying an object that's already parsed.Biotin
@bobo: All your edits are bad, please stop making them until you read up in meta.stackoverflow.com about making correct edit choices.Menam

© 2022 - 2024 — McMap. All rights reserved.