Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deep merge for JsonNode using ObjectReader.readTree() #3122

Closed
sirianni opened this issue Apr 16, 2021 · 9 comments
Closed

Deep merge for JsonNode using ObjectReader.readTree() #3122

sirianni opened this issue Apr 16, 2021 · 9 comments
Milestone

Comments

@sirianni
Copy link

sirianni commented Apr 16, 2021

Is your feature request related to a problem? Please describe.

Describe the solution you'd like
Ability to deep merge two JsonNode objects, and/or to deserialize a stream by updating an existing JsonNode rather than creating a new one.

Usage example

    var mapper = new ObjectMapper();
    var node1 = mapper.readTree("{\"root\":{\"a\":\"aaa\",\"foo\":\"hello\"}}");
    var node2 = mapper.readerForUpdating(node1)
        .readTree("{\"root\":{\"b\":\"bbb\",\"foo\":\"goodbye\"}}");

Additional context
#584 implies that this capability exists, but it does not appear to be functioning propery for JsonNode. There also doesn't seem to be a way to specify shallow or deep merge using the tree API readerForUpdating()

@sirianni sirianni added the to-evaluate Issue that has been received but not yet evaluated label Apr 16, 2021
@cowtowncoder
Copy link
Member

It should just work, with Jackson 2.12 at least. There is no (and there is unlikely ever to be a way) to select deep/shallow merge as this depends on POJOs in question (or more accurately, deserializers).

If JsonNode merge does not work, it'd be good to explain what exactly you see, and how that differs from the expectation. Ideally a unit test.

@sirianni
Copy link
Author

Thanks @cowtowncoder for the quick reply! I've created a repo https://github.com/sirianni/jsonMerge with a failing unit test.

@cowtowncoder cowtowncoder removed the to-evaluate Issue that has been received but not yet evaluated label Apr 16, 2021
@sirianni
Copy link
Author

select deep/shallow merge as this depends on POJOs in question (or more accurately, deserializers).

What are the semantics for JsonNode?

@cowtowncoder
Copy link
Member

Since JsonNode is mutable, it should allow deep merge; JsonDeserializer associated with a type should indicate this via Boolean supportsUpdate() (true, false or null (not known)).
Technically only ObjectNode and ArrayNode are updateable since leaf scalar types are immutable.

But actual implementation relies on deserialize() override which takes existing instance; if that is implemented as mutable operation, merges are possible.

@cowtowncoder
Copy link
Member

Ah. Quick fix is to use readValue(), not readTree() -- there is no benefit from trying to use readTree() here.

But I am not sure why the difference should matter and will see if that can be fixed. Thanks!

@cowtowncoder cowtowncoder changed the title Deep merge for JsonNode Deep merge for JsonNode using ObjectReader.readTree() Apr 17, 2021
@cowtowncoder cowtowncoder added 2.13 and removed 2.12 labels Apr 17, 2021
@cowtowncoder cowtowncoder added this to the 2.13.0 milestone Apr 17, 2021
@cowtowncoder
Copy link
Member

Fixed by simply delegating calls to readValue() in case "valueToUpdate" is defined; seems that this should work (and does handle tests I added). Added in 2.13 just to minimize any possibility of breakage for 2.12.x; I would recommend just using readValue() directly here in general.

@sirianni
Copy link
Author

Thanks Tatu!!

@ollijm
Copy link

ollijm commented Jun 30, 2022

@sirianni Would you happen to have a working code example of this deep merge?

@ollijm
Copy link

ollijm commented Jun 30, 2022

Ah I had a silly mistake, got it now:

        ObjectMapper mapper = new ObjectMapper();
        JsonNode node1 = mapper.readValue("{\"root\":{\"a\":\"aaa\",\"foo\":\"hello\"}}", JsonNode.class);
        JsonNode node2 = mapper.readerForUpdating(node1)
                .readValue("{\"root\":{\"b\":\"bbb\",\"foo\":\"goodbye\"}}");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants