Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package json.diff;
- import com.fasterxml.jackson.core.JsonLocation;
- import com.fasterxml.jackson.core.JsonParser;
- import com.fasterxml.jackson.core.JsonToken;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.google.common.collect.MapDifference;
- import com.google.common.collect.Maps;
- import java.io.File;
- import java.io.IOException;
- import java.io.PrintStream;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- final public class JsonDiff {
- private static final ObjectMapper mapper = new ObjectMapper();
- private JsonDiff() {
- throw new AssertionError("No instances is needed");
- }
- public static int main(final String[] args) throws IOException {
- assert args != null && args.length > 1 : "Usage: inputFile1 inputFile2 [outputFile]";
- return jsonCompare(args[0], args[1], args.length > 2 ? args[2] : null) ? 0 : 1;
- }
- static boolean jsonCompare(final String inputFile1, final String inputFile2,
- final String outputFile) throws IOException {
- final Map<String, Map<String, List<JsonLocation>>> index1 = parseJson(inputFile1);
- final Map<String, Map<String, List<JsonLocation>>> index2 = parseJson(inputFile2);
- final MapDifference<String, Map<String, Integer>> diff = Maps.difference(counts(index1), counts(index2));
- if (outputFile != null) System.setOut(new PrintStream(outputFile));
- System.out.println("Comparison of '" + inputFile1 + "' to '" + inputFile2 + "'");
- System.out.println("\nStatus: " + (diff.areEqual() ? "Success [equal]" : "Failure [mismatch]"));
- showDiff("Entries only in '" + inputFile1 + "'", diff.entriesOnlyOnLeft(), k -> showOnly(index1.get(k)));
- showDiff("Entries only in '" + inputFile2 + "'", diff.entriesOnlyOnRight(), k -> showOnly(index2.get(k)));
- showDiff("Entries differing", diff.entriesDiffering(), k -> showDiff(k, index1.get(k), index2.get(k)));
- return diff.areEqual();
- }
- private static Map<String, Map<String, List<JsonLocation>>> parseJson(final String inputFile) throws IOException {
- Map<String, Map<String, List<JsonLocation>>> m = Collections.emptyMap();
- try (final JsonParser parser = mapper.getFactory().createParser(new File(inputFile))) {
- String path = "";
- for (JsonToken token = parser.nextValue(); token != null; token = parser.nextValue()) {
- if (parser.currentName() != null) {
- final String subPath = "/" + parser.currentName();
- if (token.isStructStart()) {
- path = path + subPath;
- } else if (token.isStructEnd()) {
- final int pos = path.lastIndexOf(subPath);
- if (pos >= 0) path = path.substring(0, pos);
- } else if (token.isScalarValue()) {
- m = merge(m, Collections.singletonMap(path + subPath,
- Collections.singletonMap(parser.getValueAsString(),
- Collections.singletonList(parser.getCurrentLocation()))));
- }
- }
- }
- }
- return m;
- }
- private static <K1, K2, V> Map<K1, Map<K2, List<V>>> merge(
- final Map<K1, Map<K2, List<V>>> m1, final Map<K1, Map<K2, List<V>>> m2) {
- return Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
- (a, b) -> Stream.concat(a.entrySet().stream(), b.entrySet().stream())
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
- (x, y) -> Stream.concat(x.stream(), y.stream())
- .collect(Collectors.toList())))));
- }
- private static <K1, K2, V> Map<K1, Map<K2, Integer>> counts(final Map<K1, Map<K2, List<V>>> m) {
- return m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> counts2(e.getValue())));
- }
- private static <K, V> Map<K, Integer> counts2(final Map<K, List<V>> m) {
- return m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().size()));
- }
- private static String showOnly(final Map<String, List<JsonLocation>> index) {
- return index.entrySet().stream().map(v ->
- showLoc(v.getKey(), v.getValue(), v.getValue().size()))
- .collect(Collectors.toList()).toString();
- }
- private static <T> void showDiff(final String header, final Map<String, T> diff,
- final Function<String, String> format) {
- if (!diff.isEmpty()) {
- System.out.println("\n" + header + ":\n");
- diff.entrySet().stream().sorted(Map.Entry.comparingByKey())
- .forEach(e -> System.out.println(format.apply(e.getKey())));
- }
- }
- private static String showDiff(final String path,
- final Map<String, List<JsonLocation>> leftIndex,
- final Map<String, List<JsonLocation>> rightIndex) {
- final MapDifference<String, Integer> diff = Maps.difference(counts2(leftIndex), counts2(rightIndex));
- final List<String> left = join(diff.entriesOnlyOnLeft().keySet(), leftIndex, diff, n -> n > 0);
- final List<String> right = join(diff.entriesOnlyOnRight().keySet(), rightIndex, diff, n -> n < 0);
- return (left.isEmpty() && right.isEmpty()) ? "" : (path + " (" +
- (left.isEmpty() ? " " : left) + ", " + (right.isEmpty() ? " " : right) + ")");
- }
- private static List<String> join(final Set<String> keys, final Map<String, List<JsonLocation>> index,
- final MapDifference<String, Integer> diff,
- final Function<Integer, Boolean> f) {
- return Stream.concat(keys.stream().map(k -> Maps.immutableEntry(k, 1)),
- diff.entriesDiffering().entrySet().stream().map(e -> Maps.immutableEntry(e.getKey(),
- e.getValue().leftValue() - e.getValue().rightValue()))
- .filter(e -> f.apply(e.getValue())))
- .sorted(Map.Entry.comparingByKey())
- .map(v -> showLoc(v.getKey(), index.get(v.getKey()), Math.abs(v.getValue())))
- .collect(Collectors.toList());
- }
- private static String showLoc(final String v, final List<JsonLocation> locations, final int count) {
- return "'" + v + "':" + locations.stream().limit(count)
- .map(loc -> "" + loc.getLineNr()).collect(Collectors.joining(","));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement