Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

@Component
public class DraftCaseJsonMerger {

private static final Set<String> REPLACE_FIELDS = Set.of("address");


private final ObjectMapper objectMapper;

public DraftCaseJsonMerger(@Qualifier("draftCaseDataObjectMapper") ObjectMapper objectMapper) {
Expand All @@ -25,11 +33,45 @@ public DraftCaseJsonMerger(@Qualifier("draftCaseDataObjectMapper") ObjectMapper
*/
public String mergeJson(String baseJson, String patchJson) throws JsonProcessingException {
JsonNode base = objectMapper.readValue(baseJson, JsonNode.class);
JsonNode patch = objectMapper.readValue(patchJson, JsonNode.class);

applyReplaceRulesRecursively(base, patch);

JsonNode merged = objectMapper.readerForUpdating(base)
.readValue(patchJson);

return objectMapper.writeValueAsString(merged);
}

/**
* Clears fields in the base JSON where the patch contains an address object.
* Fully replaces the old fields rather than merging individual fields.
*/
private void applyReplaceRulesRecursively(JsonNode base, JsonNode patch) {
if (!patch.isObject() || !base.isObject()) {
return;
}

Iterator<Map.Entry<String, JsonNode>> fields = patch.properties().iterator();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String fieldName = field.getKey();
JsonNode patchChild = field.getValue();

if (base.has(fieldName)) {
JsonNode baseChild = base.get(fieldName);

if (REPLACE_FIELDS.contains(fieldName.toLowerCase())
&& patchChild.isObject()
&& base instanceof ObjectNode) {

((ObjectNode) base).set(fieldName, objectMapper.createObjectNode());

} else {
applyReplaceRulesRecursively(baseChild, patchChild);
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
import uk.gov.hmcts.reform.pcs.ccd.type.DynamicStringListElement;
import uk.gov.hmcts.reform.pcs.config.JacksonConfiguration;

import com.fasterxml.jackson.databind.JsonNode;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;


class DraftCaseJsonMergerTest {

private ObjectMapper objectMapper;
Expand Down Expand Up @@ -114,4 +117,82 @@ private DynamicStringListElement createListElement(ClaimantType value) {
return DynamicStringListElement.builder().code(value.name()).label(value.getLabel()).build();
}

@Test
void shouldClearAddressFieldsWhenPatchContainsAddress() throws Exception {
//Given
String baseJson = """
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Given

{
"party": {
"address": {
"AddressLine1": "Old Line 1",
"AddressLine2": "Old Line 2",
"AddressLine3": "Old Line 3",
"PostTown": "Old Town",
"County": "Old County",
"PostCode": "OLD123",
"Country": "Old Country"
}
}
}
""";

String patchJson = """
{
"party": {
"address": {
"AddressLine1": "New Line 1"
}
}
}
""";

// When
String mergedJson = underTest.mergeJson(baseJson, patchJson);
JsonNode merged = objectMapper.readTree(mergedJson);
JsonNode address = merged.at("/party/address");

// Then: new field present
assertThat(address.get("AddressLine1").asText()).isEqualTo("New Line 1");

// All old fields removed
assertThat(address.has("AddressLine2")).isFalse();
assertThat(address.has("AddressLine3")).isFalse();
assertThat(address.has("PostTown")).isFalse();
assertThat(address.has("County")).isFalse();
assertThat(address.has("PostCode")).isFalse();
assertThat(address.has("Country")).isFalse();
}

@Test
void shouldNotClearAddressIfPatchDoesNotContainAddress() throws Exception {
//Given
String baseJson = """
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Given

{
"party": {
"address": {
"AddressLine1": "Line 1",
"PostCode": "ABC123"
}
}
}
""";

String patchJson = """
{
"party": {
"name": "John"
}
}
""";

// When
String mergedJson = underTest.mergeJson(baseJson, patchJson);
JsonNode merged = objectMapper.readTree(mergedJson);
JsonNode address = merged.at("/party/address");

// Then: address untouched
assertThat(address.get("AddressLine1").asText()).isEqualTo("Line 1");
assertThat(address.get("PostCode").asText()).isEqualTo("ABC123");
}

}
Loading