Advertisement
Guest User

Untitled

a guest
Oct 15th, 2019
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.76 KB | None | 0 0
  1. package json.diff;
  2.  
  3. import com.fasterxml.jackson.core.JsonLocation;
  4. import com.fasterxml.jackson.core.JsonParser;
  5. import com.fasterxml.jackson.core.JsonToken;
  6. import com.fasterxml.jackson.databind.ObjectMapper;
  7. import com.google.common.collect.MapDifference;
  8. import com.google.common.collect.Maps;
  9.  
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.io.PrintStream;
  13. import java.util.Collections;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import java.util.function.Function;
  18. import java.util.stream.Collectors;
  19. import java.util.stream.Stream;
  20.  
  21. final public class JsonDiff {
  22.  
  23. private static final ObjectMapper mapper = new ObjectMapper();
  24.  
  25. private JsonDiff() {
  26. throw new AssertionError("No instances is needed");
  27. }
  28.  
  29. public static int main(final String[] args) throws IOException {
  30. assert args != null && args.length > 1 : "Usage: inputFile1 inputFile2 [outputFile]";
  31. return jsonCompare(args[0], args[1], args.length > 2 ? args[2] : null) ? 0 : 1;
  32. }
  33.  
  34. static boolean jsonCompare(final String inputFile1, final String inputFile2,
  35. final String outputFile) throws IOException {
  36. final Map<String, Map<String, List<JsonLocation>>> index1 = parseJson(inputFile1);
  37.  
  38. final Map<String, Map<String, List<JsonLocation>>> index2 = parseJson(inputFile2);
  39. final MapDifference<String, Map<String, Integer>> diff = Maps.difference(counts(index1), counts(index2));
  40.  
  41. if (outputFile != null) System.setOut(new PrintStream(outputFile));
  42. System.out.println("Comparison of '" + inputFile1 + "' to '" + inputFile2 + "'");
  43. System.out.println("\nStatus: " + (diff.areEqual() ? "Success [equal]" : "Failure [mismatch]"));
  44.  
  45. showDiff("Entries only in '" + inputFile1 + "'", diff.entriesOnlyOnLeft(), k -> showOnly(index1.get(k)));
  46. showDiff("Entries only in '" + inputFile2 + "'", diff.entriesOnlyOnRight(), k -> showOnly(index2.get(k)));
  47. showDiff("Entries differing", diff.entriesDiffering(), k -> showDiff(k, index1.get(k), index2.get(k)));
  48.  
  49. return diff.areEqual();
  50. }
  51.  
  52. private static Map<String, Map<String, List<JsonLocation>>> parseJson(final String inputFile) throws IOException {
  53. Map<String, Map<String, List<JsonLocation>>> m = Collections.emptyMap();
  54. try (final JsonParser parser = mapper.getFactory().createParser(new File(inputFile))) {
  55. String path = "";
  56. for (JsonToken token = parser.nextValue(); token != null; token = parser.nextValue()) {
  57. if (parser.currentName() != null) {
  58. final String subPath = "/" + parser.currentName();
  59. if (token.isStructStart()) {
  60. path = path + subPath;
  61. } else if (token.isStructEnd()) {
  62. final int pos = path.lastIndexOf(subPath);
  63. if (pos >= 0) path = path.substring(0, pos);
  64. } else if (token.isScalarValue()) {
  65. m = merge(m, Collections.singletonMap(path + subPath,
  66. Collections.singletonMap(parser.getValueAsString(),
  67. Collections.singletonList(parser.getCurrentLocation()))));
  68. }
  69. }
  70. }
  71. }
  72. return m;
  73. }
  74.  
  75. private static <K1, K2, V> Map<K1, Map<K2, List<V>>> merge(
  76. final Map<K1, Map<K2, List<V>>> m1, final Map<K1, Map<K2, List<V>>> m2) {
  77. return Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
  78. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
  79. (a, b) -> Stream.concat(a.entrySet().stream(), b.entrySet().stream())
  80. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
  81. (x, y) -> Stream.concat(x.stream(), y.stream())
  82. .collect(Collectors.toList())))));
  83. }
  84.  
  85. private static <K1, K2, V> Map<K1, Map<K2, Integer>> counts(final Map<K1, Map<K2, List<V>>> m) {
  86. return m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> counts2(e.getValue())));
  87. }
  88.  
  89. private static <K, V> Map<K, Integer> counts2(final Map<K, List<V>> m) {
  90. return m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().size()));
  91. }
  92.  
  93. private static String showOnly(final Map<String, List<JsonLocation>> index) {
  94. return index.entrySet().stream().map(v ->
  95. showLoc(v.getKey(), v.getValue(), v.getValue().size()))
  96. .collect(Collectors.toList()).toString();
  97. }
  98.  
  99. private static <T> void showDiff(final String header, final Map<String, T> diff,
  100. final Function<String, String> format) {
  101. if (!diff.isEmpty()) {
  102. System.out.println("\n" + header + ":\n");
  103. diff.entrySet().stream().sorted(Map.Entry.comparingByKey())
  104. .forEach(e -> System.out.println(format.apply(e.getKey())));
  105. }
  106. }
  107.  
  108. private static String showDiff(final String path,
  109. final Map<String, List<JsonLocation>> leftIndex,
  110. final Map<String, List<JsonLocation>> rightIndex) {
  111. final MapDifference<String, Integer> diff = Maps.difference(counts2(leftIndex), counts2(rightIndex));
  112. final List<String> left = join(diff.entriesOnlyOnLeft().keySet(), leftIndex, diff, n -> n > 0);
  113. final List<String> right = join(diff.entriesOnlyOnRight().keySet(), rightIndex, diff, n -> n < 0);
  114. return (left.isEmpty() && right.isEmpty()) ? "" : (path + " (" +
  115. (left.isEmpty() ? " " : left) + ", " + (right.isEmpty() ? " " : right) + ")");
  116. }
  117.  
  118. private static List<String> join(final Set<String> keys, final Map<String, List<JsonLocation>> index,
  119. final MapDifference<String, Integer> diff,
  120. final Function<Integer, Boolean> f) {
  121. return Stream.concat(keys.stream().map(k -> Maps.immutableEntry(k, 1)),
  122. diff.entriesDiffering().entrySet().stream().map(e -> Maps.immutableEntry(e.getKey(),
  123. e.getValue().leftValue() - e.getValue().rightValue()))
  124. .filter(e -> f.apply(e.getValue())))
  125. .sorted(Map.Entry.comparingByKey())
  126. .map(v -> showLoc(v.getKey(), index.get(v.getKey()), Math.abs(v.getValue())))
  127. .collect(Collectors.toList());
  128. }
  129.  
  130. private static String showLoc(final String v, final List<JsonLocation> locations, final int count) {
  131. return "'" + v + "':" + locations.stream().limit(count)
  132. .map(loc -> "" + loc.getLineNr()).collect(Collectors.joining(","));
  133. }
  134. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement