diff --git a/README.md b/README.md index 87e007c..8124f0c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ -# Apples +# reflective +Utility classes that use ASM for generating metaclasses as if it were standard java reflection, but without the performance overhead. + + +__nl.sander.reflective.compare.Compare__ * 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+ +* Can optionally do 'structural comparison' (as opposed to _nominal_ like in the respective types of polymorphism). Let's say you have class Apple with property _color_ and a class Orange, also with property _color_. `Compare` provides `any` method with which you can compare the values disregarding the type that contains them. + +__nl.sander.reflective.tomap.ToMap__ +* turn any bean/record in a Map -* 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/pom.xml b/pom.xml index 08b47df..6c855a4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,10 +3,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 nl.sander - Apples + reflective 0.0.1-SNAPSHOT - Comparator - Comparator + reflective + Reflective utils that don't use java.lang.reflect diff --git a/src/main/java/nl/sander/apples/BaseApple.java b/src/main/java/nl/sander/apples/BaseApple.java deleted file mode 100644 index 10b300f..0000000 --- a/src/main/java/nl/sander/apples/BaseApple.java +++ /dev/null @@ -1,6 +0,0 @@ -package nl.sander.apples; - -public abstract class BaseApple { - - public abstract Result compare(Object apple, Object orange); -} diff --git a/src/main/java/nl/sander/reflective/compare/AbstractComparator.java b/src/main/java/nl/sander/reflective/compare/AbstractComparator.java new file mode 100644 index 0000000..2bc7e38 --- /dev/null +++ b/src/main/java/nl/sander/reflective/compare/AbstractComparator.java @@ -0,0 +1,6 @@ +package nl.sander.reflective.compare; + +public abstract class AbstractComparator { + + public abstract Result compare(Object apple, Object orange); +} diff --git a/src/main/java/nl/sander/apples/AppleFactory.java b/src/main/java/nl/sander/reflective/compare/ComparatorFactory.java similarity index 62% rename from src/main/java/nl/sander/apples/AppleFactory.java rename to src/main/java/nl/sander/reflective/compare/ComparatorFactory.java index a2561db..cf5307b 100644 --- a/src/main/java/nl/sander/apples/AppleFactory.java +++ b/src/main/java/nl/sander/reflective/compare/ComparatorFactory.java @@ -1,5 +1,6 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; +import nl.sander.reflective.java.Java; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.tree.*; @@ -9,16 +10,14 @@ import java.util.UUID; import static org.objectweb.asm.Opcodes.*; -class AppleFactory extends ClassVisitor { +class ComparatorFactory extends ClassVisitor { - public static final String SUPER = javaName(BaseApple.class.getName()); + public static final String SUPER = Java.internalName(AbstractComparator.class); - public static final String INIT = ""; - public static final String ZERO_ARGS_VOID = "()V"; private boolean isRecord = false; - public AppleFactory() { + public ComparatorFactory() { super(ASM9); } @@ -40,52 +39,41 @@ class AppleFactory extends ClassVisitor { classNode.superName = SUPER; classNode.version = V11; classNode.access = ACC_PUBLIC; - MethodNode constructor = new MethodNode(ACC_PUBLIC, INIT, ZERO_ARGS_VOID, null, null); + MethodNode constructor = new MethodNode(ACC_PUBLIC, Java.INIT, Java.ZERO_ARGS_VOID, null, null); constructor.instructions.add(new VarInsnNode(ALOAD, 0)); - constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER, INIT, ZERO_ARGS_VOID)); + constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER, Java.INIT, Java.ZERO_ARGS_VOID)); constructor.instructions.add(new InsnNode(RETURN)); classNode.methods.add(constructor); compareMethod = new MethodNode(ACC_PUBLIC, - "compare", "(Ljava/lang/Object;Ljava/lang/Object;)Lnl/sander/apples/Result;", null, null); + "compare", "(Ljava/lang/Object;Ljava/lang/Object;)L" + Java.internalName(Result.class) + ";", null, null); classNode.methods.add(compareMethod); add(new VarInsnNode(ALOAD, 0)); } + @Override public MethodVisitor visitMethod(int access, String methodname, String desc, String signature, String[] exceptions) { - if (!hasArgs(desc) && access == Modifier.PUBLIC && isRecord || + if (!Java.hasArgs(desc) && access == Modifier.PUBLIC && isRecord || (methodname.startsWith("get") || (methodname.startsWith("is")) && desc.equals("()Z"))) { - visitGetter(methodname, asProperty(methodname, isRecord), getReturnType(desc)); + visitGetter(methodname, Java.asProperty(methodname, isRecord), Java.getReturnType(desc)); } return null; } - private String asProperty(String getter, boolean isRecord) { - if (isRecord){ - return getter; - } else { - if (getter.startsWith("get")){ - return getter.substring(3,4).toLowerCase()+getter.substring(4); - } else { - return getter.substring(2,3).toLowerCase()+getter.substring(3); - } - } - } - private void visitGetter(String getterMethodName, String propertyName, String returnType) { add(new LdcInsnNode(propertyName)); add(new VarInsnNode(ALOAD, 1)); - add(new TypeInsnNode(CHECKCAST, javaName(classToMap))); + add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap))); add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType)); add(new VarInsnNode(ALOAD, 2)); - add(new TypeInsnNode(CHECKCAST, javaName(classToMap))); + add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap))); add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType)); - add(new MethodInsnNode(INVOKESTATIC, "nl/sander/apples/Apples", "compare", "(" + add(new MethodInsnNode(INVOKESTATIC, Java.internalName(Compare.class), "compare", "(" + getSignature(returnType) - + ")Lnl/sander/apples/Result;")); + + ")L" + Java.internalName(Result.class) + ";")); add(new VarInsnNode(ASTORE, 3 + (localVarIndex++))); } @@ -96,7 +84,7 @@ class AppleFactory extends ClassVisitor { } else { type = returnType; } - return "Ljava/lang/String;"+type + type; + return "Ljava/lang/String;" + type + type; } @Override @@ -106,7 +94,7 @@ class AppleFactory extends ClassVisitor { } else { add(new LdcInsnNode(localVarIndex)); } - add(new TypeInsnNode(ANEWARRAY, "nl/sander/apples/Result")); + add(new TypeInsnNode(ANEWARRAY, Java.internalName(Result.class))); for (int i = 0; i < localVarIndex; i++) { add(new InsnNode(DUP)); @@ -119,7 +107,7 @@ class AppleFactory extends ClassVisitor { add(new InsnNode(AASTORE)); } - add(new MethodInsnNode(INVOKESTATIC, "nl/sander/apples/Result", "merge", "([Lnl/sander/apples/Result;)Lnl/sander/apples/Result;")); + add(new MethodInsnNode(INVOKESTATIC, Java.internalName(Result.class), "merge", "([L" + Java.internalName(Result.class) + ";)L" + Java.internalName(Result.class) + ";")); add(new InsnNode(ARETURN)); } @@ -127,16 +115,5 @@ class AppleFactory extends ClassVisitor { compareMethod.instructions.add(ins); } - private String getReturnType(String desc) { - return desc.substring(2); - } - - private boolean hasArgs(String desc) { - return desc.charAt(1) != ')'; - } - - private static String javaName(String className) { - return className.replaceAll("\\.", "/"); - } } diff --git a/src/main/java/nl/sander/apples/Apples.java b/src/main/java/nl/sander/reflective/compare/Compare.java similarity index 64% rename from src/main/java/nl/sander/apples/Apples.java rename to src/main/java/nl/sander/reflective/compare/Compare.java index 1968bbb..4aeb943 100644 --- a/src/main/java/nl/sander/apples/Apples.java +++ b/src/main/java/nl/sander/reflective/compare/Compare.java @@ -1,97 +1,167 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; +import nl.sander.reflective.java.ByteClassLoader; +import nl.sander.reflective.java.Java; +import nl.sander.reflective.tomap.ToMap; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.LongAdder; import java.util.stream.Collectors; import java.util.stream.Stream; @SuppressWarnings({"unchecked", "rawtypes"}) -public class Apples { +/** + * Deep (recursive) comparison of two objects + * - floating point comparison with optional precision + * - objects of same type or differing types, allowing comparison of types that have the same data or subsets + * + * In case of maps or differing object types, every item in apple is expected in orange, so apple can be subset of orange. + */ +public class Compare { private final static Map CHAR_ESCAPES = Map.of('\t', "\\t", '\b', "\\b", '\n', "\\n", '\r', "\\r", '\f', "\\f", '\\', "\\\\"); - private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader(); + private final static ConcurrentMap, AbstractComparator> cache = new ConcurrentHashMap<>(); + /** + * Compares two objects. They are assumed to be of the same type, otherwise that is the difference + * + * @param apple first object for comparison + * @param orange second object for comparison + * @return A Result object with the outcome and some details + * + * throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling) + */ public static Result compare(Object apple, Object orange) { - return compare("", apple, orange); + return compare("", apple, orange, false); } - public static Result compare(String property, Object apple, Object orange) { - if (apple == null) { - return Result.from(property, orange == null, "null != " + asString(orange)); - } + /** + * Compare two objects. They are not assumed to be of the same type. + * + * @param apple first object for comparison + * @param orange second object for comparison + * @return A Result object with the outcome and some details + * throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling) + */ + public static Result any(Object apple, Object orange) { + return compare("", apple, orange, true); + } - if (orange == null) { - return Result.unequal(property, asString(apple) + " != null"); - } + /** + * Version of same compare method where you can specify a common property for the two objects to compare. + * This is primarily useful for doing bean/record property comparison. + * + * @param property common property (key) for apple and orange + * @param apple first object for comparison + * @param orange second object for comparison + * @return A Result object with the outcome and some details + * throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling) + */ + public static Result compare(String property, Object apple, Object orange) { + return compare(property, apple, orange, false); + } - if (apple == orange) { - return Result.SAME; - } - if (apple.getClass() != orange.getClass()) { - return Result.unequal(property, asString(apple) + " != " + asString(orange)); - } - - if (apple instanceof String) { - return Result.from(property, apple.equals(orange), () -> asString(apple) + " != " + asString(orange)); - } - - if (apple instanceof Number) { - return Result.from(property, apple.equals(orange), () -> apple + " != " + orange); - } - - if (apple instanceof Collection) { - return compareCollections(property, (Collection) apple, (Collection) orange); - } - - if (apple instanceof Map) { - return compareMaps(property, (Map) apple, (Map) orange); - } - - 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, apple + " != " + orange); - } - } + static Result compare(String property, Object apple, Object orange, boolean allowDifferingTypes) { try { - ClassReader cr = new ClassReader(apple.getClass().getName()); - AppleFactory appleFactory = new AppleFactory(); - cr.accept(appleFactory, ClassReader.SKIP_FRAMES); + if (apple == null) { + return Result.from(property, orange == null, "null != " + asString(orange)); + } + + if (orange == null) { + return Result.unequal(property, asString(apple) + " != null"); + } + + if (apple == orange) { + return Result.SAME; + } + + + if (apple.getClass() != orange.getClass()) { + if (allowDifferingTypes) { + // convert objects to maps and compare their keys/values + return compareMaps(property, ToMap.map(apple), (Map) ToMap.map(orange), allowDifferingTypes); + } else { + return Result.unequal(property, asString(apple) + " != " + asString(orange)); + } + } + + if (apple instanceof String) { + return Result.from(property, apple.equals(orange), () -> asString(apple) + " != " + asString(orange)); + } + + if (apple instanceof Number) { + return Result.from(property, apple.equals(orange), () -> apple + " != " + orange); + } + + if (apple instanceof Collection) { + return compareCollections(property, (Collection) apple, (Collection) orange, allowDifferingTypes); + } + + if (apple instanceof Map) { + return compareMaps(property, (Map) apple, (Map) orange, allowDifferingTypes); + } + + 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, apple + " != " + orange); + } + } + + return cache.computeIfAbsent(apple.getClass(), k -> createComparator(apple)) + .compare(apple, orange); + } catch (Exception e) { + return Result.error(e.getCause()); + } + } + + private static AbstractComparator createComparator(Object apple) { + try { + ClassReader cr = Java.getClassReader(apple); + + ComparatorFactory comparatorFactory = new ComparatorFactory(); + cr.accept(comparatorFactory, ClassReader.SKIP_FRAMES); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - appleFactory.classNode.accept(classWriter); + comparatorFactory.classNode.accept(classWriter); byte[] byteArray = classWriter.toByteArray(); - generatedClassesLoader.addClass(appleFactory.classNode.name, byteArray); - BaseApple baseApple = (BaseApple) generatedClassesLoader.loadClass(appleFactory.classNode.name).getConstructor().newInstance(); - return baseApple.compare(apple, orange); + ByteClassLoader.INSTANCE.addClass(comparatorFactory.classNode.name, byteArray); + return (AbstractComparator) ByteClassLoader.INSTANCE.loadClass(comparatorFactory.classNode.name).getConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } - private static Result compareCollections(String property, Collection apple, Collection orange) { + private static Result compareCollections(String property, Collection apple, Collection orange, boolean allowDifferingTypes) { List diffs = zipAndEnumerate(apple, orange) - .map(t -> new Tuple4(t.e1, apple, orange, Apples.compare(property, t.e2, t.e3))) + .map(t -> { + try { + return new Tuple4(t.e1, apple, orange, Compare.compare(property, t.e2, t.e3, allowDifferingTypes)); + } catch (Exception e) { + throw new RuntimeException(e);//meh + } + }) .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 apple, Map orange) { + private static Result compareMaps(String property, Map apple, Map orange, boolean allowDifferingTypes) throws Exception { List diffs = new ArrayList<>(); 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); + Result result = Compare.compare(property + "[" + appleEntry.getKey() + "]", appleValue, orangeValue, allowDifferingTypes); if (!result.areEqual()) { diffs.addAll(result.getDiffs()); } diff --git a/src/main/java/nl/sander/apples/Result.java b/src/main/java/nl/sander/reflective/compare/Result.java similarity index 89% rename from src/main/java/nl/sander/apples/Result.java rename to src/main/java/nl/sander/reflective/compare/Result.java index 21e70b9..e4b1fbf 100644 --- a/src/main/java/nl/sander/apples/Result.java +++ b/src/main/java/nl/sander/reflective/compare/Result.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import java.util.Arrays; import java.util.List; @@ -6,18 +6,30 @@ import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Collectors; -@SuppressWarnings("unused") // used by generated code public class Result { private final boolean areEqual; private final List diffs; + private final Throwable e; + public Result(boolean areEqual, List diffs) { this.areEqual = areEqual; this.diffs = diffs; + this.e = null; } public static Result SAME = new Result(true, List.of()); + public Result(Throwable e) { + this.areEqual = false;//meh + this.diffs = null; + this.e = e; + } + + public static Result error(Throwable e) { + return new Result(e); + } + public static Result from(String property, boolean areEqual, String message) { if (!areEqual) { if (property.length() > 0) { diff --git a/src/main/java/nl/sander/apples/ByteClassLoader.java b/src/main/java/nl/sander/reflective/java/ByteClassLoader.java similarity index 68% rename from src/main/java/nl/sander/apples/ByteClassLoader.java rename to src/main/java/nl/sander/reflective/java/ByteClassLoader.java index 872baf3..3793227 100644 --- a/src/main/java/nl/sander/apples/ByteClassLoader.java +++ b/src/main/java/nl/sander/reflective/java/ByteClassLoader.java @@ -1,11 +1,17 @@ -package nl.sander.apples; +package nl.sander.reflective.java; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -class ByteClassLoader extends ClassLoader { +/* + * common util not for external use + * + * Loads the class into the jvm, after the user has generated some bytecode + */ +public class ByteClassLoader extends ClassLoader { private final ConcurrentMap> classes = new ConcurrentHashMap<>(); + public final static ByteClassLoader INSTANCE = new ByteClassLoader(); @Override protected Class findClass(String name) throws ClassNotFoundException { diff --git a/src/main/java/nl/sander/reflective/java/Java.java b/src/main/java/nl/sander/reflective/java/Java.java new file mode 100644 index 0000000..557c57c --- /dev/null +++ b/src/main/java/nl/sander/reflective/java/Java.java @@ -0,0 +1,51 @@ +package nl.sander.reflective.java; + +import org.objectweb.asm.ClassReader; + +import java.io.IOException; + +/* + * common utils not for external use + */ +public class Java { + + public static final String INIT = ""; + public static final String ZERO_ARGS_VOID = "()V"; + public static final String OBJECT = "Ljava/lang/Object;"; + + public static String internalName(String className) { + return className.replaceAll("\\.", "/"); + } + public static String internalName(Class type) { + return internalName(type.getName()); + } + public static boolean hasArgs(String desc) { + return desc.charAt(1) != ')'; + } + + public static String asProperty(String getter, boolean isRecord) { + if (isRecord) { + return getter; + } else { + if (getter.startsWith("get")) { + return getter.substring(3, 4).toLowerCase() + getter.substring(4); + } else { + return getter.substring(2, 3).toLowerCase() + getter.substring(3); + } + } + } + + public static String getReturnType(String desc) { + return desc.substring(2); + } + + public static ClassReader getClassReader(Object value) throws ClassNotFoundException { + ClassReader cr = null; + try { + cr = new ClassReader(value.getClass().getName()); + } catch (IOException e) { + throw new ClassNotFoundException(value.getClass().getName()); + } + return cr; + } +} diff --git a/src/main/java/nl/sander/reflective/tomap/AbstractToMap.java b/src/main/java/nl/sander/reflective/tomap/AbstractToMap.java new file mode 100644 index 0000000..0f987ee --- /dev/null +++ b/src/main/java/nl/sander/reflective/tomap/AbstractToMap.java @@ -0,0 +1,37 @@ +package nl.sander.reflective.tomap; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractToMap { + + public abstract Map toMap(Object object); + + protected void add(HashMap m, String key, byte b) { + m.put(key, b); + } + + protected void add(HashMap m, String key, short s) { + m.put(key, s); + } + + protected void add(HashMap m, String key, int i) { + m.put(key, i); + } + + protected void add(HashMap m, String key, boolean b) { + m.put(key, b); + } + + protected void add(HashMap m, String key, float f) { + m.put(key, f); + } + + protected void add(HashMap m, String key, double b) { + m.put(key, b); + } + + protected void add(HashMap m, String key, Object o) { + m.put(key, o); + } +} diff --git a/src/main/java/nl/sander/reflective/tomap/ToMap.java b/src/main/java/nl/sander/reflective/tomap/ToMap.java new file mode 100644 index 0000000..3cfabc0 --- /dev/null +++ b/src/main/java/nl/sander/reflective/tomap/ToMap.java @@ -0,0 +1,50 @@ +package nl.sander.reflective.tomap; + + +import nl.sander.reflective.java.ByteClassLoader; +import nl.sander.reflective.java.Java; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Turns any class (beans with getters/setters and records) into a HashMap. + */ +public class ToMap { + private static final ConcurrentMap, AbstractToMap> cache = new ConcurrentHashMap<>(); + + /** + * @param value some bean or record (so use wisely if the class is not of that pattern) + * @return Map + * @throws Exception if the class that you want to mappify somehow can't be read from the classpath + */ + public static Map map(Object value) throws Exception { + try { + return cache.computeIfAbsent(value.getClass(), k -> + createNew(value)).toMap(value); + } catch (RuntimeException e) { + throw new Exception(e.getCause()); + } + } + + private static AbstractToMap createNew(Object value) { + try{ + ClassReader cr = Java.getClassReader(value); + ToMapFactory factory = new ToMapFactory(); + cr.accept(factory, ClassReader.SKIP_FRAMES); + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + + factory.classNode.accept(classWriter); + byte[] byteArray = classWriter.toByteArray(); + + ByteClassLoader.INSTANCE.addClass(factory.classNode.name, byteArray); + return (AbstractToMap) ByteClassLoader.INSTANCE.loadClass(factory.classNode.name).getConstructor().newInstance();} + catch (Exception e){ + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/nl/sander/reflective/tomap/ToMapFactory.java b/src/main/java/nl/sander/reflective/tomap/ToMapFactory.java new file mode 100644 index 0000000..e6053ed --- /dev/null +++ b/src/main/java/nl/sander/reflective/tomap/ToMapFactory.java @@ -0,0 +1,89 @@ +package nl.sander.reflective.tomap; + +import nl.sander.reflective.java.Java; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.tree.*; + +import java.lang.reflect.Modifier; +import java.util.UUID; + +import static org.objectweb.asm.Opcodes.*; + +class ToMapFactory extends ClassVisitor { + public static final String SUPER_NAME = Java.internalName(AbstractToMap.class.getName()); + private boolean isRecord = false; + final ClassNode classNode = new ClassNode(); + + private String classToMap; + + private MethodNode mappifyMethod; + + + public ToMapFactory() { + super(ASM9); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + if (superName.equals("java/lang/Record")) { + isRecord = true; + } + this.classToMap = name; + classNode.name = "ToMap" + UUID.randomUUID(); + classNode.superName = SUPER_NAME; + classNode.version = V11; + classNode.access = ACC_PUBLIC; + MethodNode constructor = new MethodNode(ACC_PUBLIC, Java.INIT, Java.ZERO_ARGS_VOID, null, null); + constructor.instructions.add(new VarInsnNode(ALOAD, 0)); + constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER_NAME, Java.INIT, Java.ZERO_ARGS_VOID)); + constructor.instructions.add(new InsnNode(RETURN)); + classNode.methods.add(constructor); + + mappifyMethod = new MethodNode(ACC_PUBLIC, + "toMap", "(Ljava/lang/Object;)Ljava/util/Map;", null, null); + classNode.methods.add(mappifyMethod); + add(new TypeInsnNode(NEW, "java/util/HashMap")); + add(new InsnNode(DUP)); + add(new MethodInsnNode(INVOKESPECIAL, "java/util/HashMap", Java.INIT, Java.ZERO_ARGS_VOID)); + add(new VarInsnNode(ASTORE, 2)); + } + + @Override + public MethodVisitor visitMethod(int access, String methodname, + String desc, String signature, String[] exceptions) { + if (!Java.hasArgs(desc) && access == Modifier.PUBLIC && isRecord || + (methodname.startsWith("get") || (methodname.startsWith("is")) && desc.equals("()Z"))) { + visitGetter(methodname, Java.asProperty(methodname, isRecord), Java.getReturnType(desc)); + } + return null; + } + + private void visitGetter(String getterMethodName, String propertyName, String returnType) { + add(new VarInsnNode(ALOAD, 0)); + add(new VarInsnNode(ALOAD, 2)); + add(new LdcInsnNode(propertyName)); + add(new VarInsnNode(ALOAD, 1)); + add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap))); + add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType)); + add(new MethodInsnNode(INVOKEVIRTUAL, classNode.name, "add", "(Ljava/util/HashMap;Ljava/lang/String;"+translate(returnType)+")V")); + } + + private String translate(String typeDesc){ + if (typeDesc.startsWith("L")){ + return Java.OBJECT; + } else { + return typeDesc; + } + } + + @Override + public void visitEnd() { + add(new VarInsnNode(ALOAD, 2)); + add(new InsnNode(ARETURN)); + } + + private void add(AbstractInsnNode ins) { + mappifyMethod.instructions.add(ins); + } +} diff --git a/src/test/java/ExampleMappifier.java b/src/test/java/ExampleMappifier.java new file mode 100644 index 0000000..21d31d5 --- /dev/null +++ b/src/test/java/ExampleMappifier.java @@ -0,0 +1,15 @@ +import nl.sander.reflective.tomap.AbstractToMap; +import nl.sander.reflective.compare.PlumBean; + +import java.util.HashMap; +import java.util.Map; + +public class ExampleMappifier extends AbstractToMap { + + public Map toMap(Object o) { + HashMap m = new HashMap<>(); + add(m, "core", ((PlumBean) o).getCore()); + add(m, "number", ((PlumBean) o).getNumber()); + return m; + } +} diff --git a/src/test/java/nl/sander/apples/BytesTest.java b/src/test/java/nl/sander/apples/BytesTest.java deleted file mode 100644 index 8751c78..0000000 --- a/src/test/java/nl/sander/apples/BytesTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package nl.sander.apples; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class BytesTest { - - @Test - void nilEqualsNil() { - assertEquals(Result.SAME, Apples.compare((byte) 0, (byte) 0)); - } - - @Test - void nilNotEqualsSome() { - assertEquals(Result.unequal("0 != 1"), Apples.compare((byte) 0, (byte) 1)); - } - - @Test - void OneNotEqualsNil() { - assertEquals(Result.unequal("1 != 0"), Apples.compare((byte) 1, (byte) 0)); - } - - @Test - void nilByteNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Byte: 0 != 1"), Apples.compare(Byte.valueOf((byte) 0), (byte) 1)); - } - - @Test - void nilNotEqualsOneByte() { - assertEquals(Result.unequal("0 != java.lang.Byte: 1"), Apples.compare((byte) 0, Byte.valueOf((byte) 1))); - } - - @Test - void nullNotEqualsNilByte() { - assertEquals(Result.unequal("null != java.lang.Byte: 0"), Apples.compare(null, Byte.valueOf((byte) 0))); - } - - @Test - void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0"), Apples.compare(null, (byte) 0)); - } - - @Test - void nilByteNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Byte: 0 != null"), Apples.compare(Byte.valueOf((byte) 0), null)); - } - - @Test - void nilNotEqualsNull() { - assertEquals(Result.unequal("0 != null"), Apples.compare((byte) 0, null)); - } - - @Test - void byteNotEqualsString() { - assertEquals(Result.unequal("0 != \"true\""), Apples.compare((byte) 0, "true")); - } - - @Test - void StringNotEqualsByte() { - assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", (byte) 0)); - } -} diff --git a/src/test/java/nl/sander/apples/CharsTest.java b/src/test/java/nl/sander/apples/CharsTest.java deleted file mode 100644 index 83417c6..0000000 --- a/src/test/java/nl/sander/apples/CharsTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package nl.sander.apples; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class CharsTest { - - @Test - void nilEqualsNil() { - assertTrue(Apples.compare((char) 0, (char) 0).areEqual()); - } - - @Test - void nilNotEqualsSome() { - assertEquals(Result.unequal("'A' != 'B'"),Apples.compare('A', 'B')); - } - - @Test - void SomeNotEqualsNil() { - assertEquals(Result.unequal("'\\u0001' != '\\u0000'"),Apples.compare((char) 1, (char) 0)); - } - - @Test - void charEqualsCharacter() { - assertTrue(Apples.compare(Character.valueOf('X'), 'X').areEqual()); - } - - @Test - void nilNotEqualsOneCharacter() { - assertEquals(Result.unequal("'\\u0000' != '\\u0001'"),Apples.compare((char) 0, Character.valueOf((char) 1))); - } - - @Test - void nullNotEqualsNilCharacter() { - assertEquals(Result.unequal("null != '\\u0000'"),Apples.compare(null, Character.valueOf((char) 0))); - } - - @Test - void nullNotEqualsChar() { - assertEquals(Result.unequal("null != '\\u0000'"),Apples.compare(null, (char) 0)); - } - - @Test - void nilCharacterNotEqualsNull() { - assertEquals(Result.unequal("'\\u0000' != null"),Apples.compare(Character.valueOf((char) 0), null)); - } - - @Test - void charNotEqualsNull() { - assertEquals(Result.unequal("'\\u0000' != null"),Apples.compare((char) 0, null)); - } - - @Test - void charNotEqualsString() { - assertEquals(Result.unequal("'\\u0000' != \"true\""),Apples.compare((char)0, "true")); - } - - @Test - void StringNotEqualsChar() { - assertEquals(Result.unequal("\"false\" != '\\u0000'"),Apples.compare("false", (char)0)); - } -} diff --git a/src/test/java/nl/sander/apples/FloatsTest.java b/src/test/java/nl/sander/apples/FloatsTest.java deleted file mode 100644 index ef1dfa4..0000000 --- a/src/test/java/nl/sander/apples/FloatsTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package nl.sander.apples; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -@SuppressWarnings("ConstantValue") -class FloatsTest { - - @Test - void floatImprecisionLeft() { - assertTrue(Apples.compare(2 / 3F, 0.66F, 2).areEqual(), (2 / 3F) + " != " + 0.66F); - } - - @Test - void floatImprecisionRight() { - assertTrue(Apples.compare(0.66F, 2 / 3F, 2).areEqual(), (2 / 3F) + " != " + 0.66F); - } - - @Test - void nilFEqualsNilF() { - assertTrue(Apples.compare(0F, 0F).areEqual()); - } - - @Test - void nilFEqualsNilFloat() { - assertTrue(Apples.compare(0F, Float.valueOf(0)).areEqual()); - } - - @Test - void nilFEqualsNilL() { - assertTrue(Apples.compare(0F, 0L).areEqual()); - } - - @Test - void nilEqualsNilF() { - assertTrue(Apples.compare(0L, 0F).areEqual()); - } - - @Test - void nullNotEqualsSome() { - assertEquals(Result.unequal("0.0 != 1.0"), Apples.compare(0F, 1F)); - } - - @Test - void SomeNotEqualsNull() { - assertEquals(Result.unequal("1.0 != 0.0"), Apples.compare(1F, 0F)); - } - - @Test - void nilByteNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Float: 0.0 != 1.0"), Apples.compare(Float.valueOf(0), 1F)); - } - - @Test - void nilNotEqualsOneByte() { - assertEquals(Result.unequal("0.0 != java.lang.Float: 1.0"), Apples.compare(0F, Float.valueOf(1))); - } - - @Test - void nullNotEqualsNilFloat() { - assertEquals(Result.unequal("null != java.lang.Float: 0.0"), Apples.compare(null, Float.valueOf(0))); - } - - @Test - void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0.0"), Apples.compare(null, 0F)); - } - - @Test - void nilFloatNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Float: 0.0 != null"), Apples.compare(Float.valueOf(0), null)); - } - - @Test - void nilNotEqualsNull() { - assertEquals(Result.unequal("0.0 != null"), Apples.compare(0F, null)); - } - - @Test - void floatNotEqualsString() { - assertEquals(Result.unequal("0.0 != \"true\""), Apples.compare(0F, "true")); - } - - @Test - void StringNotEqualsFloat() { - assertEquals(Result.unequal("\"false\" != 0.0"), Apples.compare("false", 0F)); - } -} diff --git a/src/test/java/nl/sander/apples/LongsTest.java b/src/test/java/nl/sander/apples/LongsTest.java deleted file mode 100644 index 0cf9add..0000000 --- a/src/test/java/nl/sander/apples/LongsTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package nl.sander.apples; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class LongsTest { - - @Test - void nullEqualsNull() { - assertEquals(Result.SAME, Apples.compare(0, 0)); - } - - @Test - void nullNotEqualsSome() { - assertEquals(Result.unequal("0 != 1"), Apples.compare(0, 1)); - } - - @Test - void SomeNotEqualsNull() { - assertEquals(Result.unequal("1 != 0"), Apples.compare(1, 0)); - } - - @Test - void nilLongNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Long: 0 != 1"), Apples.compare(Long.valueOf(0), 1)); - } - - @Test - void nilNotEqualsOneLong() { - assertEquals(Result.unequal("0 != java.lang.Long: 1"), Apples.compare(0, Long.valueOf(1))); - } - - @Test - void nilEqualsNilLong() { - assertTrue(Apples.compare(0, Long.valueOf(0)).areEqual()); - } - - @Test - void nullNotEqualsNilLong() { - assertEquals(Result.unequal("null != java.lang.Long: 0"), Apples.compare(null, Long.valueOf(0))); - } - - @Test - void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0"), Apples.compare(null, 0)); - } - - @Test - void nilLongNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Long: 0 != null"), Apples.compare(Long.valueOf(0), null)); - } - - @Test - void nilNotEqualsNull() { - assertEquals(Result.unequal("0 != null"), Apples.compare(0, null)); - } - - @Test - void longNotEqualsString() { - assertEquals(Result.unequal("0 != \"0\""), Apples.compare(0, "0")); - } - - @Test - void StringNotEqualsLong() { - assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", 0)); - } -} diff --git a/src/test/java/nl/sander/apples/ShortsTest.java b/src/test/java/nl/sander/apples/ShortsTest.java deleted file mode 100644 index 90cdea1..0000000 --- a/src/test/java/nl/sander/apples/ShortsTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package nl.sander.apples; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class ShortsTest { - - @Test - void nullEqualsNull() { - assertTrue(Apples.compare((short) 0, (short) 0).areEqual()); - } - - @Test - void nullEqualsNullShort() { - assertTrue(Apples.compare((short) 0, Short.valueOf((short) 0)).areEqual()); - } - - @Test - void nullShortEqualsNull() { - assertTrue(Apples.compare(Short.valueOf((short) 0), (short) 0).areEqual()); - } - - @Test - void nullNotEqualsSome() { - assertEquals(Result.unequal("0 != 1"), Apples.compare((short) 0, (short) 1)); - } - - @Test - void SomeNotEqualsNull() { - assertEquals(Result.unequal("1 != 0"), Apples.compare((short) 1, (short) 0)); - } - - @Test - void nilshortNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Short: 0 != 1"), Apples.compare(Short.valueOf((short) 0), (short) 1)); - } - - @Test - void nilNotEqualsOneshort() { - assertEquals(Result.unequal("0 != java.lang.Short: 1"), Apples.compare((short) 0, Short.valueOf((short) 1))); - } - - @Test - void nullNotEqualsNilshort() { - assertEquals(Result.unequal("null != java.lang.Short: 0"), Apples.compare(null, Short.valueOf((short) 0))); - } - - @Test - void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0"), Apples.compare(null, (short) 0)); - } - - @Test - void nilshortNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Short: 0 != null"), Apples.compare(Short.valueOf((short) 0), null)); - } - - @Test - void nilNotEqualsNull() { - assertEquals(Result.unequal("0 != null"), Apples.compare((short) 0, null)); - } - - @Test - void shortNotEqualsString() { - assertEquals(Result.unequal("0 != \"true\""), Apples.compare((short) 0, "true")); - } - - @Test - void StringNotEqualsshort() { - assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", (short) 0)); - } -} diff --git a/src/test/java/nl/sander/apples/BeansTest.java b/src/test/java/nl/sander/reflective/compare/BeansTest.java similarity index 83% rename from src/test/java/nl/sander/apples/BeansTest.java rename to src/test/java/nl/sander/reflective/compare/BeansTest.java index e029c53..603eabb 100644 --- a/src/test/java/nl/sander/apples/BeansTest.java +++ b/src/test/java/nl/sander/reflective/compare/BeansTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -11,7 +11,7 @@ public class BeansTest { @Test void testBeans() { - Result comparison = Apples.compare(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco"))), + Result comparison = Compare.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")))); assertFalse(comparison.areEqual()); diff --git a/src/test/java/nl/sander/apples/BooleansTest.java b/src/test/java/nl/sander/reflective/compare/BooleansTest.java similarity index 54% rename from src/test/java/nl/sander/apples/BooleansTest.java rename to src/test/java/nl/sander/reflective/compare/BooleansTest.java index 8726104..2eedc18 100644 --- a/src/test/java/nl/sander/apples/BooleansTest.java +++ b/src/test/java/nl/sander/reflective/compare/BooleansTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -8,103 +8,103 @@ class BooleansTest { @Test void falseEqualsFalse() { - assertTrue(Apples.compare(false, false).areEqual()); + assertTrue(Compare.compare(false, false).areEqual()); } @Test void falseEqualsBooleanFalse() { - assertTrue(Apples.compare(false, Boolean.FALSE).areEqual()); + assertTrue(Compare.compare(false, Boolean.FALSE).areEqual()); } @Test void trueEqualsBooleanTrue() { - assertTrue(Apples.compare(true, Boolean.TRUE).areEqual()); + assertTrue(Compare.compare(true, Boolean.TRUE).areEqual()); } @Test void trueEqualsTrue() { - assertTrue(Apples.compare(true, true).areEqual()); + assertTrue(Compare.compare(true, true).areEqual()); } @Test void falseNotEqualsTrue() { - assertEquals(Result.unequal("false != true"), Apples.compare(false, true)); + assertEquals(Result.unequal("false != true"), Compare.compare(false, true)); } @Test void trueNotEqualsFalse() { - assertEquals(Result.unequal("true != false"), Apples.compare(true, false)); + assertEquals(Result.unequal("true != false"), Compare.compare(true, false)); } @Test void falseNotEqualsTrueBoolean() { - assertEquals(Result.unequal("false != java.lang.Boolean: true"), Apples.compare(false, Boolean.valueOf(true))); + assertEquals(Result.unequal("false != java.lang.Boolean: true"), Compare.compare(false, Boolean.valueOf(true))); } @Test void trueNotEqualsFalseBoolean() { - assertEquals(Result.unequal("true != java.lang.Boolean: false"), Apples.compare(true, Boolean.valueOf(false))); + assertEquals(Result.unequal("true != java.lang.Boolean: false"), Compare.compare(true, Boolean.valueOf(false))); } @Test void falseBooleanNotEqualsTrue() { - assertEquals(Result.unequal("java.lang.Boolean: false != true"), Apples.compare(Boolean.valueOf(false), true)); + assertEquals(Result.unequal("java.lang.Boolean: false != true"), Compare.compare(Boolean.valueOf(false), true)); } @Test void trueBooleanNotEqualsFalse() { - assertEquals(Result.unequal("java.lang.Boolean: true != false"), Apples.compare(Boolean.valueOf(true), false)); + assertEquals(Result.unequal("java.lang.Boolean: true != false"), Compare.compare(Boolean.valueOf(true), false)); } @Test void nullNotEqualsTrue() { - assertEquals(Result.unequal("null != true"), Apples.compare(null, true)); + assertEquals(Result.unequal("null != true"), Compare.compare(null, true)); } @Test void nullNotEqualsFalse() { - assertEquals(Result.unequal("null != false"), Apples.compare(null, false)); + assertEquals(Result.unequal("null != false"), Compare.compare(null, false)); } @Test void trueNotEqualsNull() { - assertEquals(Result.unequal("true != null"), Apples.compare(true, null)); + assertEquals(Result.unequal("true != null"), Compare.compare(true, null)); } @Test void falseNotEqualsNull() { - assertEquals(Result.unequal("false != null"), Apples.compare(false, null)); + assertEquals(Result.unequal("false != null"), Compare.compare(false, null)); } @Test void trueNotEqualsString() { - assertEquals(Result.unequal("true != \"true\""), Apples.compare(true, "true")); + assertEquals(Result.unequal("true != \"true\""), Compare.compare(true, "true")); } @Test void StringNotEqualsFalse() { - assertEquals(Result.unequal("\"false\" != false"), Apples.compare("false", false)); + assertEquals(Result.unequal("\"false\" != false"), Compare.compare("false", false)); } @Test void nullNotEqualsTrueBoolean() { - assertEquals(Result.unequal("null != java.lang.Boolean: true"), Apples.compare(null, Boolean.TRUE)); + assertEquals(Result.unequal("null != java.lang.Boolean: true"), Compare.compare(null, Boolean.TRUE)); } @Test void nullNotEqualsFalseBoolean() { - assertEquals(Result.unequal("null != java.lang.Boolean: false"), Apples.compare(null, Boolean.FALSE)); + assertEquals(Result.unequal("null != java.lang.Boolean: false"), Compare.compare(null, Boolean.FALSE)); } @Test void trueBooleanNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Boolean: true != null"), Apples.compare(Boolean.TRUE, null)); + assertEquals(Result.unequal("java.lang.Boolean: true != null"), Compare.compare(Boolean.TRUE, null)); } @Test void falseBooleanNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Boolean: false != null"), Apples.compare(Boolean.FALSE, null)); + assertEquals(Result.unequal("java.lang.Boolean: false != null"), Compare.compare(Boolean.FALSE, null)); } diff --git a/src/test/java/nl/sander/reflective/compare/BytesTest.java b/src/test/java/nl/sander/reflective/compare/BytesTest.java new file mode 100644 index 0000000..ccd894b --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/BytesTest.java @@ -0,0 +1,63 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BytesTest { + + @Test + void nilEqualsNil() { + assertEquals(Result.SAME, Compare.compare((byte) 0, (byte) 0)); + } + + @Test + void nilNotEqualsSome() { + assertEquals(Result.unequal("0 != 1"), Compare.compare((byte) 0, (byte) 1)); + } + + @Test + void OneNotEqualsNil() { + assertEquals(Result.unequal("1 != 0"), Compare.compare((byte) 1, (byte) 0)); + } + + @Test + void nilByteNotEqualsOne() { + assertEquals(Result.unequal("java.lang.Byte: 0 != 1"), Compare.compare(Byte.valueOf((byte) 0), (byte) 1)); + } + + @Test + void nilNotEqualsOneByte() { + assertEquals(Result.unequal("0 != java.lang.Byte: 1"), Compare.compare((byte) 0, Byte.valueOf((byte) 1))); + } + + @Test + void nullNotEqualsNilByte() { + assertEquals(Result.unequal("null != java.lang.Byte: 0"), Compare.compare(null, Byte.valueOf((byte) 0))); + } + + @Test + void nullNotEqualsNil() { + assertEquals(Result.unequal("null != 0"), Compare.compare(null, (byte) 0)); + } + + @Test + void nilByteNotEqualsNull() { + assertEquals(Result.unequal("java.lang.Byte: 0 != null"), Compare.compare(Byte.valueOf((byte) 0), null)); + } + + @Test + void nilNotEqualsNull() { + assertEquals(Result.unequal("0 != null"), Compare.compare((byte) 0, null)); + } + + @Test + void byteNotEqualsString() { + assertEquals(Result.unequal("0 != \"true\""), Compare.compare((byte) 0, "true")); + } + + @Test + void StringNotEqualsByte() { + assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", (byte) 0)); + } +} diff --git a/src/test/java/nl/sander/reflective/compare/CharsTest.java b/src/test/java/nl/sander/reflective/compare/CharsTest.java new file mode 100644 index 0000000..8ed555c --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/CharsTest.java @@ -0,0 +1,63 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class CharsTest { + + @Test + void nilEqualsNil() { + assertTrue(Compare.compare((char) 0, (char) 0).areEqual()); + } + + @Test + void nilNotEqualsSome() { + assertEquals(Result.unequal("'A' != 'B'"), Compare.compare('A', 'B')); + } + + @Test + void SomeNotEqualsNil() { + assertEquals(Result.unequal("'\\u0001' != '\\u0000'"), Compare.compare((char) 1, (char) 0)); + } + + @Test + void charEqualsCharacter() { + assertTrue(Compare.compare(Character.valueOf('X'), 'X').areEqual()); + } + + @Test + void nilNotEqualsOneCharacter() { + assertEquals(Result.unequal("'\\u0000' != '\\u0001'"), Compare.compare((char) 0, Character.valueOf((char) 1))); + } + + @Test + void nullNotEqualsNilCharacter() { + assertEquals(Result.unequal("null != '\\u0000'"), Compare.compare(null, Character.valueOf((char) 0))); + } + + @Test + void nullNotEqualsChar() { + assertEquals(Result.unequal("null != '\\u0000'"), Compare.compare(null, (char) 0)); + } + + @Test + void nilCharacterNotEqualsNull() { + assertEquals(Result.unequal("'\\u0000' != null"), Compare.compare(Character.valueOf((char) 0), null)); + } + + @Test + void charNotEqualsNull() { + assertEquals(Result.unequal("'\\u0000' != null"), Compare.compare((char) 0, null)); + } + + @Test + void charNotEqualsString() { + assertEquals(Result.unequal("'\\u0000' != \"true\""), Compare.compare((char) 0, "true")); + } + + @Test + void StringNotEqualsChar() { + assertEquals(Result.unequal("\"false\" != '\\u0000'"), Compare.compare("false", (char) 0)); + } +} diff --git a/src/test/java/nl/sander/reflective/compare/DifferentTypesTest.java b/src/test/java/nl/sander/reflective/compare/DifferentTypesTest.java new file mode 100644 index 0000000..1991694 --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/DifferentTypesTest.java @@ -0,0 +1,28 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DifferentTypesTest { + @Test + void testAppleAndOrange() { + assertTrue(Compare.any(new Apple("orange"), new Orange("orange")).areEqual()); + } + + class Apple { + final String color; + + Apple(String color) { + this.color = color; + } + } + + class Orange { + final String color; + + Orange(String color) { + this.color = color; + } + } +} diff --git a/src/test/java/nl/sander/apples/DoublesTest.java b/src/test/java/nl/sander/reflective/compare/DoublesTest.java similarity index 51% rename from src/test/java/nl/sander/apples/DoublesTest.java rename to src/test/java/nl/sander/reflective/compare/DoublesTest.java index 85dc5e9..30f6d5e 100644 --- a/src/test/java/nl/sander/apples/DoublesTest.java +++ b/src/test/java/nl/sander/reflective/compare/DoublesTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -8,77 +8,77 @@ class DoublesTest { @Test void floatImprecisionLeft() { - assertTrue(Apples.compare(2 / 3.0, 0.66, 2).areEqual(), (2 / 3) + " != " + 0.66); + assertTrue(Compare.compare(2 / 3.0, 0.66, 2).areEqual(), (2 / 3) + " != " + 0.66); } @Test void floatImprecisionRight() { - assertTrue(Apples.compare(0.66, 2 / 3D, 2).areEqual(), (2 / 3D) + " != " + 0.66); + assertTrue(Compare.compare(0.66, 2 / 3D, 2).areEqual(), (2 / 3D) + " != " + 0.66); } @Test void nilFEqualsNilF() { - assertTrue(Apples.compare(0.0, .0).areEqual()); + assertTrue(Compare.compare(0.0, .0).areEqual()); } @Test void nilFEqualsNilL() { - assertTrue(Apples.compare(0.0, 0L).areEqual()); + assertTrue(Compare.compare(0.0, 0L).areEqual()); } @Test void nilEqualsNilF() { - assertTrue(Apples.compare(0L, 0.0).areEqual()); + assertTrue(Compare.compare(0L, 0.0).areEqual()); } @Test void nullNotEqualsSome() { - assertEquals(Result.unequal("0.0 != 1.0"), Apples.compare(0.0, 1.0F)); + assertEquals(Result.unequal("0.0 != 1.0"), Compare.compare(0.0, 1.0F)); } @Test void SomeNotEqualsNull() { - assertEquals(Result.unequal("1.0 != 0.0"), Apples.compare(1.0, .0)); + assertEquals(Result.unequal("1.0 != 0.0"), Compare.compare(1.0, .0)); } @Test void nilDoubleNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Double: 0.0 != 1.0"), Apples.compare(Double.valueOf(0), 1F)); + assertEquals(Result.unequal("java.lang.Double: 0.0 != 1.0"), Compare.compare(Double.valueOf(0), 1F)); } @Test void nilNotEqualsOneDouble() { - assertEquals(Result.unequal("0.0 != java.lang.Double: 1.0"), Apples.compare(0F, Double.valueOf(1))); + assertEquals(Result.unequal("0.0 != java.lang.Double: 1.0"), Compare.compare(0F, Double.valueOf(1))); } @Test void nullNotEqualsNilDouble() { - assertEquals(Result.unequal("null != java.lang.Double: 0.0"), Apples.compare(null, Double.valueOf(0))); + assertEquals(Result.unequal("null != java.lang.Double: 0.0"), Compare.compare(null, Double.valueOf(0))); } @Test void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0.0"), Apples.compare(null, .0)); + assertEquals(Result.unequal("null != 0.0"), Compare.compare(null, .0)); } @Test void nilDoubleNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Double: 0.0 != null"), Apples.compare(Double.valueOf(0), null)); + assertEquals(Result.unequal("java.lang.Double: 0.0 != null"), Compare.compare(Double.valueOf(0), null)); } @Test void nilNotEqualsNull() { - assertEquals(Result.unequal("0.0 != null"), Apples.compare(.0, null)); + assertEquals(Result.unequal("0.0 != null"), Compare.compare(.0, null)); } @Test void doubleNotEqualsString() { - assertEquals(Result.unequal("0.0 != \"0\""), Apples.compare(.0, "0")); + assertEquals(Result.unequal("0.0 != \"0\""), Compare.compare(.0, "0")); } @Test void StringNotEqualsDouble() { - assertEquals(Result.unequal("\"0\" != 0.0"), Apples.compare("0", .0)); + assertEquals(Result.unequal("\"0\" != 0.0"), Compare.compare("0", .0)); } } diff --git a/src/test/java/nl/sander/reflective/compare/FloatsTest.java b/src/test/java/nl/sander/reflective/compare/FloatsTest.java new file mode 100644 index 0000000..547a0f7 --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/FloatsTest.java @@ -0,0 +1,88 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class FloatsTest { + + @Test + void floatImprecisionLeft() { + assertTrue(Compare.compare(2 / 3F, 0.66F, 2).areEqual(), (2 / 3F) + " != " + 0.66F); + } + + @Test + void floatImprecisionRight() { + assertTrue(Compare.compare(0.66F, 2 / 3F, 2).areEqual(), (2 / 3F) + " != " + 0.66F); + } + + @Test + void nilFEqualsNilF() { + assertTrue(Compare.compare(0F, 0F).areEqual()); + } + + @Test + void nilFEqualsNilFloat() { + assertTrue(Compare.compare(0F, Float.valueOf(0)).areEqual()); + } + + @Test + void nilFEqualsNilL() { + assertTrue(Compare.compare(0F, 0L).areEqual()); + } + + @Test + void nilEqualsNilF() { + assertTrue(Compare.compare(0L, 0F).areEqual()); + } + + @Test + void nullNotEqualsSome() { + assertEquals(Result.unequal("0.0 != 1.0"), Compare.compare(0F, 1F)); + } + + @Test + void SomeNotEqualsNull() { + assertEquals(Result.unequal("1.0 != 0.0"), Compare.compare(1F, 0F)); + } + + @Test + void nilByteNotEqualsOne() { + assertEquals(Result.unequal("java.lang.Float: 0.0 != 1.0"), Compare.compare(Float.valueOf(0), 1F)); + } + + @Test + void nilNotEqualsOneByte() { + assertEquals(Result.unequal("0.0 != java.lang.Float: 1.0"), Compare.compare(0F, Float.valueOf(1))); + } + + @Test + void nullNotEqualsNilFloat() { + assertEquals(Result.unequal("null != java.lang.Float: 0.0"), Compare.compare(null, Float.valueOf(0))); + } + + @Test + void nullNotEqualsNil() { + assertEquals(Result.unequal("null != 0.0"), Compare.compare(null, 0F)); + } + + @Test + void nilFloatNotEqualsNull() { + assertEquals(Result.unequal("java.lang.Float: 0.0 != null"), Compare.compare(Float.valueOf(0), null)); + } + + @Test + void nilNotEqualsNull() { + assertEquals(Result.unequal("0.0 != null"), Compare.compare(0F, null)); + } + + @Test + void floatNotEqualsString() { + assertEquals(Result.unequal("0.0 != \"true\""), Compare.compare(0F, "true")); + } + + @Test + void StringNotEqualsFloat() { + assertEquals(Result.unequal("\"false\" != 0.0"), Compare.compare("false", 0F)); + } +} diff --git a/src/test/java/nl/sander/apples/IntsTest.java b/src/test/java/nl/sander/reflective/compare/IntsTest.java similarity index 52% rename from src/test/java/nl/sander/apples/IntsTest.java rename to src/test/java/nl/sander/reflective/compare/IntsTest.java index ef5e1ce..92d8d9e 100644 --- a/src/test/java/nl/sander/apples/IntsTest.java +++ b/src/test/java/nl/sander/reflective/compare/IntsTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -8,66 +8,66 @@ class IntsTest { @Test void nilEqualsNil() { - assertEquals(Result.SAME, Apples.compare(0, 0)); + assertEquals(Result.SAME, Compare.compare(0, 0)); } @Test void nilEqualsNilInteger() { - assertEquals(Result.SAME, Apples.compare(0, Integer.valueOf(0))); + assertEquals(Result.SAME, Compare.compare(0, Integer.valueOf(0))); } @Test void nilIntegerEqualsNil() { - assertEquals(Result.SAME, Apples.compare(Integer.valueOf(0), 0)); + assertEquals(Result.SAME, Compare.compare(Integer.valueOf(0), 0)); } @Test void nullNotEqualsSome() { - assertEquals(Result.unequal("0 != 1"), Apples.compare(0, 1)); + assertEquals(Result.unequal("0 != 1"), Compare.compare(0, 1)); } @Test void SomeNotEqualsNull() { - assertEquals(Result.unequal("1 != 0"), Apples.compare(1, 0)); + assertEquals(Result.unequal("1 != 0"), Compare.compare(1, 0)); } @Test void nilByteNotEqualsOne() { - assertEquals(Result.unequal("java.lang.Integer: 0 != 1"), Apples.compare(Integer.valueOf(0), 1)); + assertEquals(Result.unequal("java.lang.Integer: 0 != 1"), Compare.compare(Integer.valueOf(0), 1)); } @Test void nilNotEqualsOneByte() { - assertEquals(Result.unequal("0 != java.lang.Integer: 1"), Apples.compare(0, Integer.valueOf(1))); + assertEquals(Result.unequal("0 != java.lang.Integer: 1"), Compare.compare(0, Integer.valueOf(1))); } @Test void nullNotEqualsNilByte() { - assertEquals(Result.unequal("null != java.lang.Integer: 0"), Apples.compare(null, Integer.valueOf(0))); + assertEquals(Result.unequal("null != java.lang.Integer: 0"), Compare.compare(null, Integer.valueOf(0))); } @Test void nullNotEqualsNil() { - assertEquals(Result.unequal("null != 0"), Apples.compare(null, 0)); + assertEquals(Result.unequal("null != 0"), Compare.compare(null, 0)); } @Test void nilByteNotEqualsNull() { - assertEquals(Result.unequal("java.lang.Integer: 0 != null"), Apples.compare(Integer.valueOf(0), null)); + assertEquals(Result.unequal("java.lang.Integer: 0 != null"), Compare.compare(Integer.valueOf(0), null)); } @Test void nilNotEqualsNull() { - assertEquals(Result.unequal("0 != null"), Apples.compare(0, null)); + assertEquals(Result.unequal("0 != null"), Compare.compare(0, null)); } @Test void intNotEqualsString() { - assertEquals(Result.unequal("0 != \"true\""), Apples.compare(0, "true")); + assertEquals(Result.unequal("0 != \"true\""), Compare.compare(0, "true")); } @Test void StringNotEqualsInt() { - assertEquals(Result.unequal("\"0\" != 0"), Apples.compare("0", 0)); + assertEquals(Result.unequal("\"0\" != 0"), Compare.compare("0", 0)); } } diff --git a/src/test/java/nl/sander/reflective/compare/LongsTest.java b/src/test/java/nl/sander/reflective/compare/LongsTest.java new file mode 100644 index 0000000..7c5c63a --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/LongsTest.java @@ -0,0 +1,68 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LongsTest { + + @Test + void nullEqualsNull() { + assertEquals(Result.SAME, Compare.compare(0, 0)); + } + + @Test + void nullNotEqualsSome() { + assertEquals(Result.unequal("0 != 1"), Compare.compare(0, 1)); + } + + @Test + void SomeNotEqualsNull() { + assertEquals(Result.unequal("1 != 0"), Compare.compare(1, 0)); + } + + @Test + void nilLongNotEqualsOne() { + assertEquals(Result.unequal("java.lang.Long: 0 != 1"), Compare.compare(Long.valueOf(0), 1)); + } + + @Test + void nilNotEqualsOneLong() { + assertEquals(Result.unequal("0 != java.lang.Long: 1"), Compare.compare(0, Long.valueOf(1))); + } + + @Test + void nilEqualsNilLong() { + assertTrue(Compare.compare(0, Long.valueOf(0)).areEqual()); + } + + @Test + void nullNotEqualsNilLong() { + assertEquals(Result.unequal("null != java.lang.Long: 0"), Compare.compare(null, Long.valueOf(0))); + } + + @Test + void nullNotEqualsNil() { + assertEquals(Result.unequal("null != 0"), Compare.compare(null, 0)); + } + + @Test + void nilLongNotEqualsNull() { + assertEquals(Result.unequal("java.lang.Long: 0 != null"), Compare.compare(Long.valueOf(0), null)); + } + + @Test + void nilNotEqualsNull() { + assertEquals(Result.unequal("0 != null"), Compare.compare(0, null)); + } + + @Test + void longNotEqualsString() { + assertEquals(Result.unequal("0 != \"0\""), Compare.compare(0, "0")); + } + + @Test + void StringNotEqualsLong() { + assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", 0)); + } +} diff --git a/src/test/java/nl/sander/apples/ObjectsTest.java b/src/test/java/nl/sander/reflective/compare/ObjectsTest.java similarity index 58% rename from src/test/java/nl/sander/apples/ObjectsTest.java rename to src/test/java/nl/sander/reflective/compare/ObjectsTest.java index 5229d4b..8945101 100644 --- a/src/test/java/nl/sander/apples/ObjectsTest.java +++ b/src/test/java/nl/sander/reflective/compare/ObjectsTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -11,32 +11,32 @@ class ObjectsTest { @Test void nullEqualsNull() { - assertTrue(Apples.compare(null, null).areEqual()); + assertTrue(Compare.compare(null, null).areEqual()); } @Test void nullNotEqualsSome() { - assertEquals(Result.unequal("null != \"some\""), Apples.compare(null, "some")); + assertEquals(Result.unequal("null != \"some\""), Compare.compare(null, "some")); } @Test void SomeNotEqualsNull() { - assertEquals(Result.unequal("\"some\" != null"), Apples.compare("some", null)); + assertEquals(Result.unequal("\"some\" != null"), Compare.compare("some", null)); } @Test void differentClass() { - assertEquals(Result.unequal("\"1\" != java.lang.Integer: 1"), Apples.compare("1", Integer.valueOf(1))); + assertEquals(Result.unequal("\"1\" != java.lang.Integer: 1"), Compare.compare("1", Integer.valueOf(1))); } @Test void sameKeysAndValues() { - assertTrue(Apples.compare("map", Map.of("a", 1, "b", 2), Map.of("b", 2, "a", 1)).areEqual()); + assertTrue(Compare.compare("map", Map.of("a", 1, "b", 2), Map.of("b", 2, "a", 1)).areEqual()); } @Test void differentKeysAndValues() { - Result result = Apples.compare("map", Map.of("a", 2, "b", 1), Map.of("b", 2, "a", 1)); + Result result = Compare.compare("map", Map.of("a", 2, "b", 1), Map.of("b", 2, "a", 1)); assertFalse(result.areEqual()); assertTrue(result.getDiffs().contains("for map[b]: 1 != 2")); assertTrue(result.getDiffs().contains("for map[a]: 2 != 1")); @@ -44,14 +44,14 @@ class ObjectsTest { @Test void bigDecimals() { - Result result = Apples.compare(BigDecimal.valueOf(0), BigDecimal.valueOf(1)); + Result result = Compare.compare(BigDecimal.valueOf(0), BigDecimal.valueOf(1)); assertFalse(result.areEqual()); assertEquals("0 != 1", result.getDiffs().get(0)); } @Test void enums() { - Result result = Apples.compare(Storage.HIGH, Storage.LOW); + Result result = Compare.compare(Storage.HIGH, Storage.LOW); assertFalse(result.areEqual()); assertEquals("HIGH != LOW", result.getDiffs().get(0)); } diff --git a/src/test/java/nl/sander/apples/PlumBean.java b/src/test/java/nl/sander/reflective/compare/PlumBean.java similarity index 96% rename from src/test/java/nl/sander/apples/PlumBean.java rename to src/test/java/nl/sander/reflective/compare/PlumBean.java index 4707ca8..fb023ea 100644 --- a/src/test/java/nl/sander/apples/PlumBean.java +++ b/src/test/java/nl/sander/reflective/compare/PlumBean.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import java.util.List; diff --git a/src/test/java/nl/sander/apples/PlumRecord.java b/src/test/java/nl/sander/reflective/compare/PlumRecord.java similarity index 100% rename from src/test/java/nl/sander/apples/PlumRecord.java rename to src/test/java/nl/sander/reflective/compare/PlumRecord.java diff --git a/src/test/java/nl/sander/apples/RecordsTest.java b/src/test/java/nl/sander/reflective/compare/RecordsTest.java similarity index 100% rename from src/test/java/nl/sander/apples/RecordsTest.java rename to src/test/java/nl/sander/reflective/compare/RecordsTest.java diff --git a/src/test/java/nl/sander/apples/Shop.java b/src/test/java/nl/sander/reflective/compare/Shop.java similarity index 89% rename from src/test/java/nl/sander/apples/Shop.java rename to src/test/java/nl/sander/reflective/compare/Shop.java index 84dae2a..6e138d1 100644 --- a/src/test/java/nl/sander/apples/Shop.java +++ b/src/test/java/nl/sander/reflective/compare/Shop.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; public class Shop { private final String name; diff --git a/src/test/java/nl/sander/reflective/compare/ShortsTest.java b/src/test/java/nl/sander/reflective/compare/ShortsTest.java new file mode 100644 index 0000000..dc8fa94 --- /dev/null +++ b/src/test/java/nl/sander/reflective/compare/ShortsTest.java @@ -0,0 +1,73 @@ +package nl.sander.reflective.compare; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ShortsTest { + + @Test + void nullEqualsNull() { + assertTrue(Compare.compare((short) 0, (short) 0).areEqual()); + } + + @Test + void nullEqualsNullShort() { + assertTrue(Compare.compare((short) 0, Short.valueOf((short) 0)).areEqual()); + } + + @Test + void nullShortEqualsNull() { + assertTrue(Compare.compare(Short.valueOf((short) 0), (short) 0).areEqual()); + } + + @Test + void nullNotEqualsSome() { + assertEquals(Result.unequal("0 != 1"), Compare.compare((short) 0, (short) 1)); + } + + @Test + void SomeNotEqualsNull() { + assertEquals(Result.unequal("1 != 0"), Compare.compare((short) 1, (short) 0)); + } + + @Test + void nilshortNotEqualsOne() { + assertEquals(Result.unequal("java.lang.Short: 0 != 1"), Compare.compare(Short.valueOf((short) 0), (short) 1)); + } + + @Test + void nilNotEqualsOneshort() { + assertEquals(Result.unequal("0 != java.lang.Short: 1"), Compare.compare((short) 0, Short.valueOf((short) 1))); + } + + @Test + void nullNotEqualsNilshort() { + assertEquals(Result.unequal("null != java.lang.Short: 0"), Compare.compare(null, Short.valueOf((short) 0))); + } + + @Test + void nullNotEqualsNil() { + assertEquals(Result.unequal("null != 0"), Compare.compare(null, (short) 0)); + } + + @Test + void nilshortNotEqualsNull() { + assertEquals(Result.unequal("java.lang.Short: 0 != null"), Compare.compare(Short.valueOf((short) 0), null)); + } + + @Test + void nilNotEqualsNull() { + assertEquals(Result.unequal("0 != null"), Compare.compare((short) 0, null)); + } + + @Test + void shortNotEqualsString() { + assertEquals(Result.unequal("0 != \"true\""), Compare.compare((short) 0, "true")); + } + + @Test + void StringNotEqualsshort() { + assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", (short) 0)); + } +} diff --git a/src/test/java/nl/sander/apples/Storage.java b/src/test/java/nl/sander/reflective/compare/Storage.java similarity index 53% rename from src/test/java/nl/sander/apples/Storage.java rename to src/test/java/nl/sander/reflective/compare/Storage.java index bf7f895..0c12c18 100644 --- a/src/test/java/nl/sander/apples/Storage.java +++ b/src/test/java/nl/sander/reflective/compare/Storage.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; public enum Storage { HIGH, diff --git a/src/test/java/nl/sander/apples/StringTest.java b/src/test/java/nl/sander/reflective/compare/StringTest.java similarity index 52% rename from src/test/java/nl/sander/apples/StringTest.java rename to src/test/java/nl/sander/reflective/compare/StringTest.java index dd3dffa..43cc666 100644 --- a/src/test/java/nl/sander/apples/StringTest.java +++ b/src/test/java/nl/sander/reflective/compare/StringTest.java @@ -1,4 +1,4 @@ -package nl.sander.apples; +package nl.sander.reflective.compare; import org.junit.jupiter.api.Test; @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; class StringTest { @Test - void test() { - assertTrue(Apples.compare("left", "left").areEqual()); + void test() { + assertTrue(Compare.compare("left", "left").areEqual()); } } diff --git a/src/test/java/nl/sander/reflective/tomap/ToMapTest.java b/src/test/java/nl/sander/reflective/tomap/ToMapTest.java new file mode 100644 index 0000000..c234f02 --- /dev/null +++ b/src/test/java/nl/sander/reflective/tomap/ToMapTest.java @@ -0,0 +1,30 @@ +package nl.sander.reflective.tomap; + +import nl.sander.reflective.compare.PlumBean; +import nl.sander.reflective.compare.Shop; +import nl.sander.reflective.compare.Storage; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class ToMapTest { + @Test + void testBeans() throws Exception { + Map map = ToMap.map(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco")))); + assertEquals("small", map.get("core")); + assertEquals("red", map.get("peel")); + assertEquals(true, map.get("juicy")); + assertEquals(1, map.get("number")); + assertEquals(1.0F, map.get("price")); + assertEquals(Storage.HIGH, map.get("storage")); + assertEquals((byte)1, map.get("cores")); + Object shops = map.get("shops"); + assertTrue(shops instanceof List); + List shopsList = (List) shops; + assertEquals(1, shopsList.size()); + assertEquals("tesco", shopsList.get(0).getName()); + } +}