diff --git a/README.md b/README.md index 69b9488..87e007c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Apples -* universal compare tool -* compares any to any and shows the diff +* universal (deep) compare tool +* compares [apple] to [orange] recursively and shows the diff * no reflection * compiles to bytecode version jdk11 * but also handles records, if you run jdk16+ + +* I have one more wish for this and that is 'structural comparison'. Let's say you have class Apple with property _color_ and a class Orange, also with property _color_. Right now `Apples` does the sensible thing, and that is saying: "classes don't match". But what what if you could compare these apples and oranges? Should be possible. \ No newline at end of file diff --git a/src/main/java/nl/sander/apples/AppleFactory.java b/src/main/java/nl/sander/apples/AppleFactory.java index f4b8a7a..a2561db 100644 --- a/src/main/java/nl/sander/apples/AppleFactory.java +++ b/src/main/java/nl/sander/apples/AppleFactory.java @@ -38,7 +38,7 @@ class AppleFactory extends ClassVisitor { this.classToMap = name; classNode.name = "Apple" + UUID.randomUUID(); classNode.superName = SUPER; - classNode.version = V1_8; + classNode.version = V11; classNode.access = ACC_PUBLIC; MethodNode constructor = new MethodNode(ACC_PUBLIC, INIT, ZERO_ARGS_VOID, null, null); constructor.instructions.add(new VarInsnNode(ALOAD, 0)); diff --git a/src/main/java/nl/sander/apples/Apples.java b/src/main/java/nl/sander/apples/Apples.java index 05e08e7..1968bbb 100644 --- a/src/main/java/nl/sander/apples/Apples.java +++ b/src/main/java/nl/sander/apples/Apples.java @@ -14,53 +14,53 @@ public class Apples { private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader(); - public static Result compare(Object left, Object right) { - return compare("", left, right); + public static Result compare(Object apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, Object left, Object right) { - if (left == null) { - return Result.from(property, right == null, "null != " + asString(right)); + public static Result compare(String property, Object apple, Object orange) { + if (apple == null) { + return Result.from(property, orange == null, "null != " + asString(orange)); } - if (right == null) { - return Result.unequal(property, asString(left) + " != null"); + if (orange == null) { + return Result.unequal(property, asString(apple) + " != null"); } - if (left == right) { + if (apple == orange) { return Result.SAME; } - if (left.getClass() != right.getClass()) { - return Result.unequal(property, asString(left) + " != " + asString(right)); + if (apple.getClass() != orange.getClass()) { + return Result.unequal(property, asString(apple) + " != " + asString(orange)); } - if (left instanceof String) { - return Result.from(property, left.equals(right), () -> asString(left) + " != " + asString(right)); + if (apple instanceof String) { + return Result.from(property, apple.equals(orange), () -> asString(apple) + " != " + asString(orange)); } - if (left instanceof Number) { - return Result.from(property, left.equals(right), () -> left + " != " + right); + if (apple instanceof Number) { + return Result.from(property, apple.equals(orange), () -> apple + " != " + orange); } - if (left instanceof Collection) { - return compareCollections(property, (Collection) left, (Collection) right); + if (apple instanceof Collection) { + return compareCollections(property, (Collection) apple, (Collection) orange); } - if (left instanceof Map) { - return compareMaps(property, (Map) left, (Map) right); + if (apple instanceof Map) { + return compareMaps(property, (Map) apple, (Map) orange); } - if (left instanceof Comparable) { - int comparison = ((Comparable) left).compareTo(right); + if (apple instanceof Comparable) { + int comparison = ((Comparable) apple).compareTo(orange); if (comparison == 0) { return new Result(true, List.of()); } else { - return Result.from(property, false, left + " != " + right); + return Result.from(property, false, apple + " != " + orange); } } try { - ClassReader cr = new ClassReader(left.getClass().getName()); + ClassReader cr = new ClassReader(apple.getClass().getName()); AppleFactory appleFactory = new AppleFactory(); cr.accept(appleFactory, ClassReader.SKIP_FRAMES); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); @@ -69,29 +69,29 @@ public class Apples { byte[] byteArray = classWriter.toByteArray(); generatedClassesLoader.addClass(appleFactory.classNode.name, byteArray); - BaseApple apple = (BaseApple) generatedClassesLoader.loadClass(appleFactory.classNode.name).getConstructor().newInstance(); - return apple.compare(left, right); + BaseApple baseApple = (BaseApple) generatedClassesLoader.loadClass(appleFactory.classNode.name).getConstructor().newInstance(); + return baseApple.compare(apple, orange); } catch (Exception e) { throw new RuntimeException(e); } } - private static Result compareCollections(String property, Collection left, Collection right) { + private static Result compareCollections(String property, Collection apple, Collection orange) { List diffs = - zipAndEnumerate(left, right) - .map(t -> new Tuple4(t.e1, left, right, Apples.compare(property, t.e2, t.e3))) + zipAndEnumerate(apple, orange) + .map(t -> new Tuple4(t.e1, apple, orange, Apples.compare(property, t.e2, t.e3))) .filter(t -> !t.e4.areEqual()) .map(t -> property + "[" + t.e1 + "]:" + t.e2 + " != " + t.e3) .collect(Collectors.toList()); return new Result(!diffs.isEmpty(), diffs); } - private static Result compareMaps(String property, Map left, Map right) { + private static Result compareMaps(String property, Map apple, Map orange) { List diffs = new ArrayList<>(); - for (Map.Entry leftEntry : left.entrySet()) { - Object leftValue = leftEntry.getValue(); - Object rightValue = right.get(leftEntry.getKey()); - Result result = Apples.compare(property + "[" + leftEntry.getKey() + "]", leftValue, rightValue); + for (Map.Entry appleEntry : apple.entrySet()) { + Object appleValue = appleEntry.getValue(); + Object orangeValue = orange.get(appleEntry.getKey()); + Result result = Apples.compare(property + "[" + appleEntry.getKey() + "]", appleValue, orangeValue); if (!result.areEqual()) { diffs.addAll(result.getDiffs()); } @@ -99,187 +99,187 @@ public class Apples { return new Result(diffs.isEmpty(), diffs); } - private static Stream> zipAndEnumerate(Collection left, Collection right) { - Iterator rightIt = right.iterator(); + private static Stream> zipAndEnumerate(Collection apple, Collection orange) { + Iterator orangeListIterator = orange.iterator(); LongAdder adder = new LongAdder(); - return left.stream() - .filter(__ -> rightIt.hasNext()) + return apple.stream() + .filter(__ -> orangeListIterator.hasNext()) .map(o -> { - Tuple3 next = new Tuple3<>(adder.intValue(), o, rightIt.next()); + Tuple3 next = new Tuple3<>(adder.intValue(), o, orangeListIterator.next()); adder.increment(); return next; }); } - public static Result compare(long left, long right) { - return compare("", left, right); + public static Result compare(long apple, long orange) { + return compare("", apple, orange); } - public static Result compare(String property, long left, long right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, long apple, long orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(int left, int right) { - return compare("", left, right); + public static Result compare(int apple, int orange) { + return compare("", apple, orange); } - public static Result compare(String property, int left, int right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, int apple, int orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(short left, short right) { - return compare("", left, right); + public static Result compare(short apple, short orange) { + return compare("", apple, orange); } - public static Result compare(String property, short left, short right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, short apple, short orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(byte left, byte right) { - return compare("", left, right); + public static Result compare(byte apple, byte orange) { + return compare("", apple, orange); } - public static Result compare(String property, byte left, byte right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, byte apple, byte orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(float left, float right) { - return compare("", left, right); + public static Result compare(float apple, float orange) { + return compare("", apple, orange); } - public static Result compare(String property, float left, float right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, float apple, float orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(Object left, long right) { - return compare("", left, right); + public static Result compare(Object apple, long orange) { + return compare("", apple, orange); } - public static Result compare(String property, Object left, long right) { - if (left == null) { - return Result.unequal(property, "null != " + right); + public static Result compare(String property, Object apple, long orange) { + if (apple == null) { + return Result.unequal(property, "null != " + orange); } - if (left instanceof Long) { - return Result.from(property, (Long) left == right, asString(left) + " != " + right); - } else if (left instanceof Integer) { - return Result.from(property, (Integer) left == right, asString(left) + " != " + right); - } else if (left instanceof Short) { - return Result.from(property, (Short) left == right, asString(left) + " != " + right); - } else if (left instanceof Byte) { - return Result.from(property, (Byte) left == right, asString(left) + " != " + right); + if (apple instanceof Long) { + return Result.from(property, (Long) apple == orange, asString(apple) + " != " + orange); + } else if (apple instanceof Integer) { + return Result.from(property, (Integer) apple == orange, asString(apple) + " != " + orange); + } else if (apple instanceof Short) { + return Result.from(property, (Short) apple == orange, asString(apple) + " != " + orange); + } else if (apple instanceof Byte) { + return Result.from(property, (Byte) apple == orange, asString(apple) + " != " + orange); } else { - return Result.unequal(property, asString(left) + " != " + right); + return Result.unequal(property, asString(apple) + " != " + orange); } } - public static Result compare(char left, char right) { - return compare("", left, right); + public static Result compare(char apple, char orange) { + return compare("", apple, orange); } - public static Result compare(String property, char left, char right) { - return Result.from(property, left == right, asString(left) + " != " + asString(right)); + public static Result compare(String property, char apple, char orange) { + return Result.from(property, apple == orange, asString(apple) + " != " + asString(orange)); } - public static Result compare(Object left, char right) { - return compare("", left, right); + public static Result compare(Object apple, char orange) { + return compare("", apple, orange); } - public static Result compare(String property, Object left, char right) { - return Result.from(property, left instanceof Character && (Character) left == right, asString(left) + " != " + asString(right)); + public static Result compare(String property, Object apple, char orange) { + return Result.from(property, apple instanceof Character && (Character) apple == orange, asString(apple) + " != " + asString(orange)); } - public static Result compare(long left, Object right) { - return compare("", left, right); + public static Result compare(long apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, long left, Object right) { - if (right == null) { - return Result.unequal(property, left + " != null"); + public static Result compare(String property, long apple, Object orange) { + if (orange == null) { + return Result.unequal(property, apple + " != null"); } - if (right instanceof Long) { - return Result.from(property, (Long) right == left, left + " != " + asString(right)); - } else if (right instanceof Integer) { - return Result.from(property, (Integer) right == left, left + " != " + asString(right)); - } else if (right instanceof Short) { - return Result.from(property, (Short) right == left, left + " != " + asString(right)); - } else if (right instanceof Byte) { - return Result.from(property, (Byte) right == left, left + " != " + asString(right)); + if (orange instanceof Long) { + return Result.from(property, (Long) orange == apple, apple + " != " + asString(orange)); + } else if (orange instanceof Integer) { + return Result.from(property, (Integer) orange == apple, apple + " != " + asString(orange)); + } else if (orange instanceof Short) { + return Result.from(property, (Short) orange == apple, apple + " != " + asString(orange)); + } else if (orange instanceof Byte) { + return Result.from(property, (Byte) orange == apple, apple + " != " + asString(orange)); } else { - return Result.unequal(property, left + " != " + asString(right)); + return Result.unequal(property, apple + " != " + asString(orange)); } } - public static Result compare(char left, Object right) { - return compare("", left, right); + public static Result compare(char apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, char left, Object right) { - return Result.from(property, right instanceof Character && left == (Character) right, asString(left) + " != " + asString(right)); + public static Result compare(String property, char apple, Object orange) { + return Result.from(property, orange instanceof Character && apple == (Character) orange, asString(apple) + " != " + asString(orange)); } - public static Result compare(boolean left, boolean right) { - return compare("", left, right); + public static Result compare(boolean apple, boolean orange) { + return compare("", apple, orange); } - public static Result compare(String property, boolean left, boolean right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, boolean apple, boolean orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(Object left, boolean right) { - return compare("", left, right); + public static Result compare(Object apple, boolean orange) { + return compare("", apple, orange); } - public static Result compare(String property, Object left, boolean right) { - return Result.from(property, left instanceof Boolean && (Boolean) left == right, asString(left) + " != " + right); + public static Result compare(String property, Object apple, boolean orange) { + return Result.from(property, apple instanceof Boolean && (Boolean) apple == orange, asString(apple) + " != " + orange); } - public static Result compare(boolean left, Object right) { - return compare("", left, right); + public static Result compare(boolean apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, boolean left, Object right) { - return Result.from(property, right instanceof Boolean && left == (Boolean) right, left + " != " + asString(right)); + public static Result compare(String property, boolean apple, Object orange) { + return Result.from(property, orange instanceof Boolean && apple == (Boolean) orange, apple + " != " + asString(orange)); } - public static Result compare(double left, double right) { - return compare("", left, right); + public static Result compare(double apple, double orange) { + return compare("", apple, orange); } - public static Result compare(String property, double left, double right) { - return Result.from(property, left == right, left + " != " + right); + public static Result compare(String property, double apple, double orange) { + return Result.from(property, apple == orange, apple + " != " + orange); } - public static Result compare(double left, double right, int precision) { - return compare("", left, right, precision); + public static Result compare(double apple, double orange, int precision) { + return compare("", apple, orange, precision); } - public static Result compare(String property, double left, double right, int precision) { - return Result.from(property, (int) (left * Math.pow(10, precision)) == (int) (right * Math.pow(10, precision)), left + " != " + right + ", using precision" + precision); + public static Result compare(String property, double apple, double orange, int precision) { + return Result.from(property, (int) (apple * Math.pow(10, precision)) == (int) (orange * Math.pow(10, precision)), apple + " != " + orange + ", using precision" + precision); } - public static Result compare(Object left, double right) { - return compare("", left, right); + public static Result compare(Object apple, double orange) { + return compare("", apple, orange); } - public static Result compare(String property, Object left, double right) { - return Result.from(property, left instanceof Double && (Double) left == right, asString(left) + " != " + right); + public static Result compare(String property, Object apple, double orange) { + return Result.from(property, apple instanceof Double && (Double) apple == orange, asString(apple) + " != " + orange); } - public static Result compare(double left, Object right) { - return compare("", left, right); + public static Result compare(double apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, double left, Object right) { - return Result.from(property, right instanceof Double && left == (Double) right, left + " != " + asString(right)); + public static Result compare(String property, double apple, Object orange) { + return Result.from(property, orange instanceof Double && apple == (Double) orange, apple + " != " + asString(orange)); } - public static Result compare(float left, Object right) { - return compare("", left, right); + public static Result compare(float apple, Object orange) { + return compare("", apple, orange); } - public static Result compare(String property, float left, Object right) { - return Result.from(property, right instanceof Float && left == (Float) right, left + " != " + asString(right)); + public static Result compare(String property, float apple, Object orange) { + return Result.from(property, orange instanceof Float && apple == (Float) orange, apple + " != " + asString(orange)); } private static String asString(char value) { diff --git a/src/main/java/nl/sander/apples/BaseApple.java b/src/main/java/nl/sander/apples/BaseApple.java index 2144aa5..10b300f 100644 --- a/src/main/java/nl/sander/apples/BaseApple.java +++ b/src/main/java/nl/sander/apples/BaseApple.java @@ -1,6 +1,6 @@ package nl.sander.apples; -public abstract class BaseApple { +public abstract class BaseApple { - public abstract Result compare(T left, T right); + public abstract Result compare(Object apple, Object orange); } diff --git a/src/test/java/nl/sander/apples/BeansTest.java b/src/test/java/nl/sander/apples/BeansTest.java index c6ed7d1..e029c53 100644 --- a/src/test/java/nl/sander/apples/BeansTest.java +++ b/src/test/java/nl/sander/apples/BeansTest.java @@ -7,10 +7,10 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -class BeansTest { +public class BeansTest { @Test - void testRecords() { + void testBeans() { Result comparison = Apples.compare(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco"))), new PlumBean("large", "green", true, 1, 1.0F, Storage.LOW, (byte) 1, List.of(new Shop("asda"))));