java-json-tools/json-patch

Problem with ObjectIds

heruan opened this issue · 2 comments

Patching and deserializing object annotated with JsonIdentityInfo may fail when duplicate ids occur. For example, given a JSON source:

{
    "@id": 123,
    "name": "John",
    "dog": { "@id": 456, "name": "Buddy" },
    "cat": { "@id": 789, "name": "Rover" },
    "favoritePet": 456
}

applying

[ {
    "op": "replace",
    "path": "/favoritePet",
    "value": { "@id": 789, "name": "Rover" }
} ]

will result in

{
    "@id": 123,
    "name": "John",
    "dog": { "@id": 456, "name": "Buddy" },
    "cat": { "@id": 789, "name": "Rover" },
    "favoritePet": { "@id": 789, "name": "Rover" }
}

and deserializing with Jackson will fail with:

JsonMappingException: Already had POJO for id '789'

The patch is applied correctly, but it cannot be deserialized as a side effect of duplicated ObjectIds. Id would be useful to have JsonPatch recognize ObjectIds and use them if the patched JSON already contains one.

Despite being a java implementation of json-patch, json-patch itself is a broader internet standard. Not sure if adding something in to support a deserialization framework like Jackson is the right direction. I could be misunderstanding.

That's true, it may be an additional plugin. I managed to achieve the desired result with a simple for-loop:

JsonNode patchedState = jsonPatch.apply(currentState);

Set<String> visited = new HashSet<>();

for (JsonNode node : patchedState.findParents("@id")) {
    String identity = node.get("@id").asText();
    ObjectNode objectNode = (ObjectNode) node;
    if (visited.contains(identity)) {
        objectNode.removeAll();
        objectNode.put("@ref", identity);
    } else {
        visited.add(identity);
    }
}

This works when the ObjectId generator is JSOG-compliant.