Skip to content

Add new operations to existing jsonpatch file

I’m working on a test suite for some Java code that uses jsonpatch to modify db entries. What I am trying to do is have a template jsonpatch request saved down as a file that individual unit tests could read from, modify some operations, and then call the patch directly.

The rough structure is as follows:

jsonpatch template:

"jsonPatch": [
  {
    "op": "replace",
    "path": "/username",
    "value": "johnDoe"
  },
  {
    "op": "replace",
    "path": "/number",
    "value": 123
  }
]

java code:

// Import Template
JsonPatch request;
InputStream is = TestRestTemplate.class.getResourceAsStream("/PatchRequest.json");
request = objectMapper.readValue(is, JsonPatch.class)

// Modify Operations (not working)
Random r = new Random();
int newNumber = r.nextInt(100);
((ObjectNode) request).put("/number", newNumber);  // this doesn't even compile due to conversion issues

// Send patch
thingThatTouchesDB.patchDocument(request)

// Validate Results
int finalNumber = [get field from DB]
assertEquals(newNumber, finalNumber);

When I comment out the modify operation section everything works so I’m not having issues with importing or sending the patch. My struggle is with updating the template’s operations to fit. The paths are the same across tests but I need to try with different values each time since we’re using a persistent database for testing.

Is there a way to modify the value of an existing jsonpatch operation like I’m trying above? Failing that, can I add new operations to the existing jsonpatch?

Answer

After a lot of trial and error I got it to work by modifying the inputstream itself instead of the jsonpatch object.

I added some targets to the json template and did stream replacement on a copy of the inputstream to force in my desired values before converting it all into the final jsonpatch.

new template:

"jsonPatch": [
  {
    "op": "replace",
    "path": "/username",
    "value": "$username$"
  },
  {
    "op": "replace",
    "path": "/number",
    "value": "$number$"
  }
]

new code:

// Import Template
JsonPatch request;
InputStream is = TestRestTemplate.class.getResourceAsStream("/PatchRequest.json");
byte[] bytes = FileCopyUtils.copyToByteArray(is);
String requestStr= new String(bytes);
    
// Modify Operations
Random r = new Random();
int newNumber = r.nextInt(100);
requestStr= requestStr.replaceAll(""\$number\$"", String.valueOf(newNumber));
requestStr= requestStr.replaceAll("\$username\$", "NewName");

// Finalize Request
request = objectMapper.readValue(requestStr, JsonPatch.class)

Getting the number value to work was a bit tricky since everything is strings, but I was able to crack it by having the replace operation get rid of its quotes which causes it to get picked up as a number by the jsonpatch.