Skip to content

Commit ef013c9

Browse files
authored
feat: upgrade to Jackson 3.x and Java 21 (#27)
- Migrate from Jackson 2.15.2 to Jackson 3.0.3 (new tools.jackson package) - Upgrade Java target from 11 to 21 - Update test dependencies: JUnit 5.10.2, Mockito 5.21.0 - Add CLAUDE.md for AI-assisted development
1 parent e001606 commit ef013c9

31 files changed

+208
-163
lines changed

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414

1515
steps:
1616
- uses: actions/checkout@v3
17-
- name: Set up JDK 11
17+
- name: Set up JDK 21
1818
uses: actions/setup-java@v3
1919
with:
20-
java-version: '11'
20+
java-version: '21'
2121
distribution: 'temurin'
2222
server-id: github
2323
settings-path: ${{ github.workspace }}

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313

1414
steps:
1515
- uses: actions/checkout@v3
16-
- name: Set up JDK 11
16+
- name: Set up JDK 21
1717
uses: actions/setup-java@v3
1818
with:
19-
java-version: '11'
19+
java-version: '21'
2020
distribution: 'temurin'
2121
- name: Setup gradle
2222
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1

CLAUDE.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build Commands
6+
7+
```bash
8+
# Build the project
9+
./gradlew build
10+
11+
# Run all tests
12+
./gradlew test
13+
14+
# Run a single test class
15+
./gradlew test --tests "com.deblock.jsondiff.matcher.LenientJsonArrayPartialMatcherTest"
16+
17+
# Run a single test method
18+
./gradlew test --tests "com.deblock.jsondiff.DiffGeneratorTest.singleDiff"
19+
20+
# Create JAR
21+
./gradlew jar
22+
23+
# Publish to Maven local
24+
./gradlew publishToMavenLocal
25+
```
26+
27+
## Architecture
28+
29+
This library compares two JSON documents and produces a diff with a similarity score (0-100).
30+
31+
### Core Components
32+
33+
**Entry Point:** `DiffGenerator.diff(expectedJson, actualJson, jsonMatcher)` parses JSON strings and delegates to matchers.
34+
35+
**Matcher Layer** (`com.deblock.jsondiff.matcher`):
36+
- `CompositeJsonMatcher` - Combines different matchers for objects, arrays, and primitives
37+
- `PartialJsonMatcher<T>` - Interface for type-specific matching strategies
38+
- Two modes available:
39+
- **Strict:** `StrictJsonObjectPartialMatcher`, `StrictJsonArrayPartialMatcher`, `StrictPrimitivePartialMatcher`
40+
- **Lenient:** `LenientJsonObjectPartialMatcher` (ignores extra properties), `LenientJsonArrayPartialMatcher` (ignores order/extra items), `LenientNumberPrimitivePartialMatcher` (10.0 == 10)
41+
42+
**Diff Representation** (`com.deblock.jsondiff.diff`):
43+
- `JsonDiff` - Interface with `similarityRate()` and `display(viewer)` methods
44+
- `JsonObjectDiff` - Object comparison result (similarity = 60% structure + 40% values)
45+
- `JsonArrayDiff` - Array comparison result (similarity = average of matched items)
46+
- `MatchedPrimaryDiff` / `UnMatchedPrimaryDiff` - Primitive comparison results
47+
48+
**Viewer Layer** (`com.deblock.jsondiff.viewer`):
49+
- `JsonDiffViewer` - Visitor interface for consuming diff results
50+
- `OnlyErrorDiffViewer` - Human-readable error list output
51+
- `PatchDiffViewer` - Unified diff format output
52+
53+
### Design Patterns
54+
55+
- **Visitor Pattern:** JsonDiffViewer consumes JsonDiff via `display(viewer)` method
56+
- **Strategy Pattern:** Different PartialJsonMatcher implementations for different comparison modes
57+
- **Composite Pattern:** CompositeJsonMatcher combines object/array/primitive matchers
58+
59+
### Path Tracking
60+
61+
`Path` class tracks JSON location (e.g., `$.property.0.subproperty`) using `PathItem` subclasses (`ObjectProperty`, `ArrayIndex`).

build.gradle

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ repositories {
2020
}
2121

2222
dependencies {
23-
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
24-
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
25-
testImplementation 'org.mockito:mockito-core:3.8.0'
23+
implementation 'tools.jackson.core:jackson-databind:3.0.3'
24+
testImplementation platform('org.junit:junit-bom:5.10.2')
25+
testImplementation 'org.junit.jupiter:junit-jupiter'
26+
testImplementation 'org.mockito:mockito-core:5.21.0'
2627
}
2728

2829
group = 'io.github.deblockt'
@@ -50,8 +51,8 @@ java {
5051
withJavadocJar()
5152
withSourcesJar()
5253

53-
sourceCompatibility = JavaLanguageVersion.of(11)
54-
targetCompatibility = JavaLanguageVersion.of(11)
54+
sourceCompatibility = JavaLanguageVersion.of(21)
55+
targetCompatibility = JavaLanguageVersion.of(21)
5556
}
5657

5758
test {

src/main/java/com/deblock/jsondiff/DiffGenerator.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import com.deblock.jsondiff.diff.JsonDiff;
44
import com.deblock.jsondiff.matcher.JsonMatcher;
55
import com.deblock.jsondiff.matcher.Path;
6-
import com.fasterxml.jackson.core.JsonProcessingException;
7-
import com.fasterxml.jackson.databind.JsonNode;
8-
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import tools.jackson.core.JacksonException;
7+
import tools.jackson.databind.JsonNode;
8+
import tools.jackson.databind.ObjectMapper;
99

1010
import java.util.List;
1111
import java.util.stream.Collectors;
@@ -27,7 +27,7 @@ public static List<JsonDiff> diff(String expected, List<String> actualValues, Js
2727
private static JsonNode read(String json) {
2828
try {
2929
return OBJECT_MAPPER.readTree(json);
30-
} catch (JsonProcessingException e) {
30+
} catch (JacksonException e) {
3131
throw new JsonReadException(e);
3232
}
3333
}

src/main/java/com/deblock/jsondiff/diff/JsonArrayDiff.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.deblock.jsondiff.matcher.Path;
44
import com.deblock.jsondiff.viewer.JsonDiffViewer;
5-
import com.fasterxml.jackson.databind.JsonNode;
5+
import tools.jackson.databind.JsonNode;
66

77
import java.util.HashMap;
88
import java.util.Map;

src/main/java/com/deblock/jsondiff/diff/JsonObjectDiff.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import com.deblock.jsondiff.matcher.Path;
44
import com.deblock.jsondiff.viewer.JsonDiffViewer;
5-
import com.fasterxml.jackson.databind.JsonNode;
6-
import com.fasterxml.jackson.databind.node.ObjectNode;
5+
import tools.jackson.databind.JsonNode;
6+
import tools.jackson.databind.node.ObjectNode;
77

88
import java.util.HashMap;
99
import java.util.Map;

src/main/java/com/deblock/jsondiff/diff/MatchedPrimaryDiff.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.deblock.jsondiff.matcher.Path;
44
import com.deblock.jsondiff.viewer.JsonDiffViewer;
5-
import com.fasterxml.jackson.databind.JsonNode;
5+
import tools.jackson.databind.JsonNode;
66

77
public class MatchedPrimaryDiff implements JsonDiff {
88
private final JsonNode value;

src/main/java/com/deblock/jsondiff/diff/UnMatchedPrimaryDiff.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.deblock.jsondiff.matcher.Path;
44
import com.deblock.jsondiff.viewer.JsonDiffViewer;
5-
import com.fasterxml.jackson.databind.JsonNode;
5+
import tools.jackson.databind.JsonNode;
66

77
public class UnMatchedPrimaryDiff implements JsonDiff {
88
private final JsonNode expectedValue;

src/main/java/com/deblock/jsondiff/matcher/CompositeJsonMatcher.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.deblock.jsondiff.matcher;
22

33
import com.deblock.jsondiff.diff.*;
4-
import com.fasterxml.jackson.databind.JsonNode;
5-
import com.fasterxml.jackson.databind.node.ArrayNode;
6-
import com.fasterxml.jackson.databind.node.ObjectNode;
7-
import com.fasterxml.jackson.databind.node.ValueNode;
4+
import tools.jackson.databind.JsonNode;
5+
import tools.jackson.databind.node.ArrayNode;
6+
import tools.jackson.databind.node.ObjectNode;
7+
import tools.jackson.databind.node.ValueNode;
88

99
public class CompositeJsonMatcher implements JsonMatcher {
1010
private final PartialJsonMatcher<ArrayNode> jsonArrayPartialMatcher;
@@ -23,12 +23,12 @@ public CompositeJsonMatcher(
2323

2424
@Override
2525
public JsonDiff diff(Path path, JsonNode expected, JsonNode received) {
26-
if (expected instanceof ObjectNode && received instanceof ObjectNode) {
27-
return this.jsonObjectPartialMatcher.jsonDiff(path, (ObjectNode) expected, (ObjectNode) received, this);
28-
} else if (expected instanceof ArrayNode && received instanceof ArrayNode) {
29-
return this.jsonArrayPartialMatcher.jsonDiff(path, (ArrayNode) expected, (ArrayNode) received, this);
30-
} else if (expected instanceof ValueNode && received instanceof ValueNode){
31-
return this.primitivePartialMatcher.jsonDiff(path, (ValueNode) expected, (ValueNode) received, this);
26+
if (expected instanceof ObjectNode expectedObjectNode && received instanceof ObjectNode receivedObjectNode) {
27+
return this.jsonObjectPartialMatcher.jsonDiff(path, expectedObjectNode, receivedObjectNode, this);
28+
} else if (expected instanceof ArrayNode expectedArrayNode && received instanceof ArrayNode receivedArrayNode) {
29+
return this.jsonArrayPartialMatcher.jsonDiff(path, expectedArrayNode, receivedArrayNode, this);
30+
} else if (expected instanceof ValueNode expectedValueNode && received instanceof ValueNode receivedValueNode){
31+
return this.primitivePartialMatcher.jsonDiff(path, expectedValueNode, receivedValueNode, this);
3232
} else {
3333
return new UnMatchedPrimaryDiff(path, expected, received);
3434
}

0 commit comments

Comments
 (0)