Skip to content

Commit 3081c04

Browse files
committed
initial commit
0 parents  commit 3081c04

34 files changed

+2349
-0
lines changed

README.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Json Comparison
2+
General Json Comparison, but includes various features of interest.
3+
4+
# Summary
5+
An advanced JSON Comparison tool that takes two strings (JSON strings) as input and outputs a diff result. The diff result includes missing fields, changed(modified) fields, and new(unexpected) fields. By default, a different order is considered a difference.
6+
In order to forgive re-ordering, a values or exclude path filters option can assist by providing a path (regex).
7+
8+
# Advantages
9+
This project provide a full unique solution for JSON comparison including:
10+
* Simple difference result structure divided by type (new, missing and modified fields);
11+
* Ability to ignore specific path;
12+
* Ability to ignore order difference in particular path;
13+
14+
# How Does This Json Comparison Library Offer Value
15+
There is no doubt that many Java projects are dealing with Json comparison, so why do we need another project?
16+
17+
Most existing projects are <b>only</b> suitable for writing tests that compare two JSON inputs. The existing libraries provide <b>assert</b> methods that answer a closed question 'Are the two JSON Strings Equal?' and they may throw an exception when the two inputs are different. This is ideal for test usage. However, these projects make it hard to integrate JSON comparison results into business logic that decision makers depend on. It is also difficult for summaries and reports from comparison results.
18+
19+
Moreover some existing projects do not support features such as 'Ignore Paths' or 'Ignore Order.' As a result, existing tools may be useful for simple use only.
20+
21+
This project provides a full solution for JSON comparison. In particular if you need to integrate and manipulate comparison results into your business logic, this framework will be useful. In addition, if you are looking for comparison that includes advanced features like 'Ignore Paths' and 'Ignore Order,' this framework wll be of value.
22+
23+
# Features
24+
* Simple difference result structure divided by type ( new, missing and modified fields )
25+
* Ability to ignore specific path
26+
* Ability to ignore order difference in particular path
27+
* The project use the same JSON Comparison Engine as used in https://github.com/skyscreamer/JSONassert
28+
29+
---
30+
# Examples
31+
32+
```
33+
String expectedJson = "{}";
34+
String actualJson = "{}";
35+
36+
JsonComparisonResult compareResult = JsonCompare.builder()
37+
.addFilter(new IgnoredNewValuesFilter(Paths.createRegexPaths("root\\.ignore\\.new\\.field")))
38+
.addFilter(new IgnoredPathFilter(Paths.createRegexPaths("root\\.ignore\\.path\\..*"))) // .* match the prefix root.ignore.path.value
39+
.ignoreOrder(Paths.createRegexPaths("root\\.array"))
40+
.build()
41+
.compare(expectedJson, actualJson);
42+
43+
boolean isMatch = compareResult.isMatch();
44+
```
45+
46+
47+
# Filters
48+
Json Comparison supports 4 kind of filters
49+
* Ignore new field/value filter IgnoredNewValueFilter.class - ignore diff on a new field/value (exists in actual JSON only)
50+
* Ignore missing/value field filter IgnoredMissingValuesFilter.class - ignore diff on a missing field or value (exists in expected JSON only)
51+
* Ignore modified values filter IgnoredModifiedValuesFilter.class - ignore diff on a modified value (exists in actual or expected JSON)
52+
* Ignore path filter IgnoredPathFilter.class - ignore diff field or value in both sides
53+
54+
Note: also supports custom Filter
55+
56+
57+
# Order
58+
Json Comparison, by default, uses a STRICT mode - all arrays in JSON should preserve order.
59+
In order to ignore order use the ignoreOrder option.
60+
61+
62+
# Paths
63+
<p>
64+
Json Comparison supports Json Path syntax, since Paths are regular expression paths, and backslash is required for an escape character See https://www.vogella.com/tutorials/JavaRegularExpressions/article.html#backslashes-in-java
65+
</p>
66+
67+
68+
```Json
69+
Path for secondElement is rootElement\\.secondElement
70+
71+
{
72+
"rootElement": {
73+
"secondElement" : "value"
74+
}
75+
}
76+
```
77+
78+
```JSON
79+
Path for first item value in array "rootElement\\.array\\[1\\]\\.item.value"
80+
81+
{
82+
"rootElement": {
83+
"array": [
84+
{
85+
"item": "value"
86+
},
87+
{
88+
"item": "value2"
89+
}
90+
]
91+
}
92+
}
93+
```
94+
95+
```JSON
96+
Path for all elements start with A rootElement\\.startWithA.*
97+
98+
{
99+
"rootElement": {
100+
"startWithA1": {
101+
"item": "value"
102+
},
103+
"startWithA2": {
104+
"item": "value"
105+
}
106+
}
107+
}
108+
```
109+
110+
##### Note: Json Comparison always expects a full Path always. If you provide a partial path, then add a suffix .* to match the rest of the path.
111+
112+
# Results - CompareJsonResult
113+
Json Comparison returns 3 collections
114+
* modifiedFields - fields that have different values
115+
* missingFields - fields that are missing in expected JSON
116+
* newFields - fields that are extra in expected JSON, but do not exists in actual JSON
117+
118+
# QuickStart
119+
To use, download the JAR, or add the following to your project's pom.xml:
120+
```
121+
<dependency>
122+
<groupId>com.json.comparison</groupId>
123+
<artifactId>json-comparison</artifactId>
124+
<version>1.2</version>
125+
</dependency>
126+
```
127+
128+
Write comparison of two strings:
129+
```
130+
131+
JsonComparisonResult compareResult = JsonCompare.builder()
132+
.build()
133+
.compare(expectedJson, actualJson);
134+
```
135+
136+
#New Contributions
137+
New contributions from the community are welcome.<br/>
138+
Ideas for features that could be implemented by contributors include:
139+
* Improve Path syntax
140+
* Ability to compare particular path only
141+
* Creating GUI for the result
142+
143+
# License
144+
Copyright 2019 eBay Inc. <BR>
145+
Author/Developer: Ahmad Mahagna
146+
147+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
148+
149+
https://www.apache.org/licenses/LICENSE-2.0
150+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
151+
152+
# Notice of 3rd Party Code Use
153+
This project includes code from the open source project(s) listed below.
154+
155+
JSONAssert <BR>
156+
========== <BR>
157+
URL: https://github.com/skyscreamer/JSONassert <BR>
158+
LICENSE: Apache License, found at: https://github.com/skyscreamer/JSONassert/blob/master/LICENSE.txt

pom.xml

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.json.comparison</groupId>
8+
<artifactId>comparison-core</artifactId>
9+
<version>1.2</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
</properties>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>org.skyscreamer</groupId>
18+
<artifactId>jsonassert</artifactId>
19+
<version>1.5.0</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.apache.commons</groupId>
23+
<artifactId>commons-lang3</artifactId>
24+
<version>3.8.1</version>
25+
</dependency>
26+
<!-- -->
27+
<dependency>
28+
<groupId>org.mockito</groupId>
29+
<artifactId>mockito-core</artifactId>
30+
<version>2.23.4</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>junit</groupId>
34+
<artifactId>junit</artifactId>
35+
<version>4.12</version>
36+
<scope>test</scope>
37+
</dependency>
38+
<dependency>
39+
<groupId>com.google.guava</groupId>
40+
<artifactId>guava</artifactId>
41+
<version>27.0-jre</version>
42+
<scope>test</scope>
43+
</dependency>
44+
</dependencies>
45+
46+
<build>
47+
<plugins>
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-compiler-plugin</artifactId>
51+
<version>3.6.0</version>
52+
<configuration>
53+
<source>1.8</source>
54+
<target>1.8</target>
55+
</configuration>
56+
</plugin>
57+
</plugins>
58+
</build>
59+
60+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/************************************************************************
2+
Copyright 2019 eBay Inc.
3+
Author/Developer(s): Ahmad Mahagna
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
https://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
**************************************************************************/
17+
package com.json.comparison;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.apache.commons.lang3.builder.ToStringBuilder;
23+
24+
import com.json.comparison.comprator.DefaultJsonComparator;
25+
import com.json.comparison.comprator.JsonComparator;
26+
import com.json.comparison.comprator.model.Paths;
27+
import com.json.comparison.comprator.model.api.JsonComparatorResult;
28+
import com.json.comparison.converter.JsonComparatorConverter;
29+
import com.json.comparison.filter.ComparatorFilter;
30+
31+
/**
32+
* A JsonCompare class represents the main class of the project that can take two Json and return all differences
33+
*
34+
* Basic Usage no filters return all differences in the result
35+
*
36+
* JsonComparisonResult compare = JsonCompare.builder()
37+
* .build()
38+
* .compare(expectedJson, actualJson);
39+
*
40+
*
41+
* Usage with filters and ignore order
42+
*
43+
* JsonComparisonResult compare = JsonCompare.builder()
44+
* .addFilter(new IgnoredPathFilter(Paths.createRegexPaths(ignorePath)))
45+
* .ignoreOrder(Paths.createRegexPaths(ignoredOrder))
46+
* .build()
47+
* .compare(expectedJson, actualJson);
48+
*
49+
*/
50+
public class JsonCompare {
51+
52+
private final JsonComparator jsonComparator;
53+
private final Paths ignoreOrder;
54+
private final List<ComparatorFilter> filters;
55+
56+
private JsonCompare(JsonCompareBuilder builder) {
57+
jsonComparator = builder.jsonComparator;
58+
ignoreOrder = builder.ignoreOrder;
59+
filters = builder.filters;
60+
}
61+
62+
public static JsonCompareBuilder builder() {
63+
return new JsonCompareBuilder();
64+
}
65+
66+
public JsonComparisonResult compare(String expected, String actual) {
67+
68+
JsonComparatorResult result = filters.stream()
69+
.reduce(jsonComparator.compare(expected, actual, ignoreOrder), (res, comparatorFilter) -> comparatorFilter.filter(res),
70+
(filterBefore, filterAfter) -> filterAfter);
71+
return buildResult(actual, expected, result);
72+
}
73+
74+
private JsonComparisonResult buildResult(String actual, String expected,
75+
JsonComparatorResult jsonComparatorResult) {
76+
77+
return JsonComparisonResultImpl.builder()
78+
.actual(actual)
79+
.expected(expected)
80+
.modifiedFields(jsonComparatorResult.getModifiedFields())
81+
.missingFields(jsonComparatorResult.getMissingFields())
82+
.newFields(jsonComparatorResult.getNewFields())
83+
.build();
84+
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return new ToStringBuilder(this).append("jsonComparator", jsonComparator)
90+
.append("ignoreOrder", ignoreOrder)
91+
.append("filters", filters)
92+
.toString();
93+
}
94+
95+
public static final class JsonCompareBuilder {
96+
97+
private JsonComparator jsonComparator = new DefaultJsonComparator(new JsonComparatorConverter());
98+
private Paths ignoreOrder = Paths.createRegexPaths();
99+
private List<ComparatorFilter> filters = new ArrayList<>();
100+
101+
private JsonCompareBuilder() {
102+
103+
}
104+
105+
public JsonCompareBuilder jsonComparator(JsonComparator jsonComparator) {
106+
this.jsonComparator = jsonComparator;
107+
return this;
108+
}
109+
110+
public JsonCompareBuilder ignoreOrder(Paths ignoreOrder) {
111+
this.ignoreOrder = ignoreOrder;
112+
return this;
113+
}
114+
115+
public JsonCompareBuilder addFilter(ComparatorFilter filter) {
116+
this.filters.add(filter);
117+
return this;
118+
}
119+
120+
public JsonCompare build() {
121+
return new JsonCompare(this);
122+
}
123+
}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/************************************************************************
2+
Copyright 2019 eBay Inc.
3+
Author/Developer(s): Ahmad Mahagna
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
https://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
**************************************************************************/
17+
package com.json.comparison;
18+
19+
import java.util.Collection;
20+
21+
import com.json.comparison.comprator.model.api.FieldComparison;
22+
23+
/**
24+
* A JsonComparisonResult interface represents the final result include the actual and expected Jsons
25+
* the <code>isMatch</code> return true if the two given Jsons are match
26+
* @See JsonComparatorResult
27+
*/
28+
public interface JsonComparisonResult {
29+
30+
String getActual();
31+
32+
String getExpected();
33+
34+
boolean isMatch();
35+
36+
Collection<FieldComparison> getModifiedFields();
37+
38+
Collection<FieldComparison> getMissingFields();
39+
40+
Collection<FieldComparison> getNewFields();
41+
42+
}

0 commit comments

Comments
 (0)