From 3cd7639da1775028c4e55817c3141863a23f4610 Mon Sep 17 00:00:00 2001 From: Isaac Parenteau Date: Mon, 18 Sep 2023 18:32:52 -0500 Subject: [PATCH] More unit tests for jdk17 --- .../common/annotations/MapValue.java | 2 +- .../net/locusworks/common/utils/Utils.java | 198 +++++++----------- .../java/net/locusworks/test/UtilsTest.java | 134 +++++++++++- 3 files changed, 212 insertions(+), 122 deletions(-) diff --git a/src/main/java/net/locusworks/common/annotations/MapValue.java b/src/main/java/net/locusworks/common/annotations/MapValue.java index b1845e7..951698d 100644 --- a/src/main/java/net/locusworks/common/annotations/MapValue.java +++ b/src/main/java/net/locusworks/common/annotations/MapValue.java @@ -13,7 +13,7 @@ import java.lang.annotation.Target; * @author Isaac Parenteau * */ -@Target({ElementType.FIELD, ElementType.TYPE}) +@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MapValue { diff --git a/src/main/java/net/locusworks/common/utils/Utils.java b/src/main/java/net/locusworks/common/utils/Utils.java index 2257988..95af3d4 100644 --- a/src/main/java/net/locusworks/common/utils/Utils.java +++ b/src/main/java/net/locusworks/common/utils/Utils.java @@ -4,17 +4,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -24,8 +14,6 @@ import java.util.stream.IntStream; import net.locusworks.common.annotations.MapValue; import net.locusworks.common.interfaces.ThrowingConsumer; -import java.util.Set; - /*** * Utils class with generic methods * @author Isaac Parenteau @@ -110,49 +98,33 @@ public class Utils { */ @SuppressWarnings("unchecked") public static Map buildMap(Class mapClass, Class mapKey, Class mapValue, Object... data) { + Objects.requireNonNull(mapKey, "Null key value"); + Objects.requireNonNull(mapValue, "Null map value"); + Map results; try { results = (Map) mapClass.getDeclaredConstructor().newInstance(); } catch (Exception ex) { - throw new IllegalArgumentException("Unable to create instance of " + mapClass.getSimpleName()); + throw new IllegalArgumentException("Unable to create instance of " + mapClass.getSimpleName() + " e: " + ex.getMessage()); } if (data.length % 2 != 0) { throw new IllegalArgumentException("Odd number of arguments provided"); } - Object key = null; - int step = -1; + for(int i = 0; i < data.length; i+=2) { + Object key = data[i]; + Object value = data[i + 1]; - for (Object value : data) { - switch(++step % 2) { - case 0: - if (mapKey == null) { - throw new IllegalArgumentException("Null key value"); - } - if (value instanceof Class) { - try { - value = ((Class)value).getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new IllegalArgumentException("Unable to create new instance of " + value); - } - } - - if (!mapKey.isInstance(value)) { - throw new IllegalArgumentException("Key is not the correct instance. Expecting " + mapKey.getName() + " Received " + value.getClass().getName()); - } - - key = value; - continue; - case 1: - if (!mapValue.isInstance(value)) { - throw new IllegalArgumentException("Value is not the correct instance. Expecting " + mapValue.getName() + " Received " + value.getClass().getName()); - } - results.put((K) key, (V) value); - break; - default: - throw new IllegalAccessError("Calculation for step was not a multiple of two. This shouldn't have happened"); + if (!mapKey.isInstance(key)) { + throw new IllegalArgumentException("Key is not the correct instance. Expecting " + mapKey.getName() + " Received " + key.getClass().getName()); } + + if (!mapValue.isInstance(value)) { + throw new IllegalArgumentException("Value is not the correct instance. Expecting " + mapValue.getName() + " Received " + value.getClass().getName()); + } + results.put((K) key, (V) value); + } return results; } @@ -161,28 +133,24 @@ public class Utils { * Builds a set of objects * @param setClass Class type of the set to create * @param setValue Class type of the objects being placed in the set - * @param Class type of the return object (should be the same as setValue) + * @param Class type of the return object (should be the same as setValue) * @param data Data to place inside the set * @return Set filled with the data + * @deprecated since JDk11 can use Set.of */ @SuppressWarnings("unchecked") - public static Set buildSet(Class setClass, Class setValue, Object... data) { - Set results; + public static Set buildSet(Class setClass, Class setValue, E... data) { + return buildSet(data); + } - try { - results = (Set) setClass.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new IllegalArgumentException("Unable to create instance of " + setClass.getSimpleName()); - } - - for (Object value : data) { - if (!setValue.isInstance(value)) { - throw new IllegalArgumentException("Value is not the correct instance. Expecting " + setValue.getName() + " Received " + value.getClass().getName()); - } - results.add((V) value); - } - - return results; + /** + * Builds a set of objects + * @param data the data to set + * @return the set + * @param the type + */ + @SafeVarargs public static Set buildSet(E... data) { + return Set.of(data); } /** @@ -197,23 +165,12 @@ public class Utils { } /** - * Clone list. + * Clone list and makes it unmodifiable. * - * @param the type parameter - * @param list the list - * - * @return the list - * @throws IllegalAccessException throw when an object in the list cannot be accessed through reflection - * @throws InstantiationException thrown when an object in the list cannot be instantiated through reflection + * @return unmodifiable list */ - @SuppressWarnings("unchecked") - public static List cloneList(List list) - throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { - List clone = new ArrayList<>(); - for (E item : list) { - clone.add((E) cloneObject(item)); - } - return clone; + public static List cloneList(List list) { + return Collections.unmodifiableList(list); } /** @@ -223,7 +180,8 @@ public class Utils { * @throws IllegalAccessException thrown when the filed cannot be access * @throws InstantiationException Thrown when the object cannot be instantiated */ - public static Object cloneObject(Object obj) + @SuppressWarnings("unchecked") + public static O cloneObject(O obj) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Object clone = obj.getClass().getDeclaredConstructor().newInstance(); for (Field field : obj.getClass().getDeclaredFields()) { @@ -232,9 +190,10 @@ public class Utils { if (field.get(obj) == null || Modifier.isFinal(field.getModifiers())){ continue; } - if (field.getType().isPrimitive() || field.getType().equals(String.class) - || field.getType().getSuperclass().equals(Number.class) - || field.getType().equals(Boolean.class)){ + + Class type = field.getType(); + + if (type.isPrimitive() || getWrapperTypes().contains(type)) { field.set(clone, field.get(obj)); } else { Object childObj = field.get(obj); @@ -246,7 +205,7 @@ public class Utils { } } catch (NullPointerException ignored) { } } - return clone; + return (O) clone; } /*** @@ -260,18 +219,17 @@ public class Utils { Class clazz = obj.getClass(); Map map = new LinkedHashMap<>(); - boolean hasAnnotations = clazz.isAnnotationPresent(MapValue.class); + for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); + boolean hasAnnotations = field.isAnnotationPresent(MapValue.class); + String key = field.getName(); Object value = field.get(obj); if (value == null) continue; if (hasAnnotations) { - if (!field.isAnnotationPresent(MapValue.class)) { - continue; - } MapValue annotation = field.getDeclaredAnnotation(MapValue.class); if (annotation.ignore()) { continue; @@ -303,6 +261,12 @@ public class Utils { return convert; } + /** + * Converts an object toa string map; + * @param obj the object to convert + * @return the map + * @throws Exception thrown if something happens + */ public static Map convertToStringMap(Object obj) throws Exception { return convertToStringMap(convertToMap(obj)); } @@ -459,6 +423,27 @@ public class Utils { return tmpList; } + /** + * Use reflection to get the field values + * @param clazz the class to find the field + * @param fieldName the field name + * @return field + */ + private static Field getField(Class clazz, String fieldName) { + Field field = null; + while(clazz != null) { + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + break; + } catch(Exception ex) { + clazz = clazz.getSuperclass(); + } + } + + return field; + } + /** * A replacement for String.format. Allows for to many parameters or too few * Replaces {} in the string in order. @@ -503,27 +488,6 @@ public class Utils { return obj == null ? "Unknown" : (verbose ? obj.getClass().getName() : obj.getClass().getSimpleName()); } - /** - * Use reflection to get the field values - * @param clazz the class to find the field - * @param fieldName the field name - * @return field - */ - private static Field getField(Class clazz, String fieldName) { - Field field = null; - while(clazz != null) { - try { - field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - break; - } catch(Exception ex) { - clazz = clazz.getSuperclass(); - } - } - - return field; - } - /** * Get a value from a map * @@ -1076,16 +1040,16 @@ public class Utils { } private static Set> getWrapperTypes() { - Set> ret = new HashSet<>(); - ret.add(Boolean.class); - ret.add(Character.class); - ret.add(Byte.class); - ret.add(Short.class); - ret.add(Integer.class); - ret.add(Long.class); - ret.add(Float.class); - ret.add(Double.class); - ret.add(String.class); - return ret; + return Set.of( + Boolean.class, + Character.class, + Byte.class, + Short.class, + Integer.class, + Long.class, + Float.class, + Double.class, + String.class + ); } } diff --git a/src/test/java/net/locusworks/test/UtilsTest.java b/src/test/java/net/locusworks/test/UtilsTest.java index 389e0dd..cd324c5 100644 --- a/src/test/java/net/locusworks/test/UtilsTest.java +++ b/src/test/java/net/locusworks/test/UtilsTest.java @@ -1,15 +1,14 @@ package net.locusworks.test; +import net.locusworks.common.annotations.MapValue; import net.locusworks.common.utils.Utils; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.ParameterizedTest; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; +import java.lang.reflect.InvocationTargetException; +import java.util.*; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -110,9 +109,136 @@ public class UtilsTest { assertEquals("World", mymap.get("Hello")); } + @Test + public void testCloneList() { + String[] values = new String[]{ + "Hello", + "world" + }; + List cloned = Utils.cloneList(new ArrayList<>(Arrays.stream(values).toList())); + assertEquals(2, cloned.size()); + assertThrows(UnsupportedOperationException.class, () -> cloned.add("asdf")); + } + + @Test + public void testCloneObject() + throws InvocationTargetException, InstantiationException, IllegalAccessException, + NoSuchMethodException { + TestClass clazz = new TestClass(); + clazz.field1 = "hi"; + clazz.field2 = "low"; + clazz.field3 = "world"; + + TestClass clazz3 = new TestClass(); + clazz3.field1 = "hi"; + clazz3.field2 = "smash"; + clazz3.field3 = "world"; + + clazz.testClass = clazz3; + + TestClass clazz2 = Utils.cloneObject(clazz); + assertNotNull(clazz2); + assertEquals(clazz.field1, clazz2.field1); + assertEquals(clazz.field2, clazz2.field2); + assertEquals(clazz.field3, clazz2.field3); + assertEquals(clazz.field5, clazz2.field5); + assertEquals(clazz.number, clazz2.number); + assertEquals(clazz.aBoolean, clazz2.aBoolean); + assertNotNull(clazz2.field4); + assertNull(clazz2.nullField); + } + + @Test + public void testCovertToMap() throws Exception { + TestClass clazz = new TestClass(); + clazz.field1 = "hi"; + clazz.field2 = "low"; + clazz.field3 = "world"; + + TestClass clazz3 = new TestClass(); + clazz.field1 = "hi"; + clazz.field2 = "low"; + clazz.field3 = "world"; + clazz.testClass = clazz3; + + Map converted = Utils.convertToMap(clazz); + + assertEquals(7, converted.size()); + assertEquals("hi", converted.get("other_field")); + } + + @Test + public void testConvertToStringMap() throws Exception { + TestClass clazz = new TestClass(); + clazz.field1 = "hi"; + clazz.field2 = "low"; + clazz.field3 = "world"; + Map converted = Utils.convertToStringMap(clazz); + assertEquals(6, converted.size()); + assertEquals("hi", converted.get("other_field")); + + converted = Utils.convertToStringMap(converted); + assertEquals(6, converted.size()); + assertEquals("hi", converted.get("other_field")); + } + + @Test + public void testBuildStringMap() { + Map myMap = Utils.buildStringHashMap("hello", "world"); + assertNotNull(myMap); + assertEquals(1, myMap.size()); + } + + @Test + public void testBuildMapExceptions() { + Throwable ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(String.class, String.class, String.class, "" )); + + assertNotNull(ex); + + ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello")); + + assertEquals("Odd number of arguments provided", ex.getMessage()); + + assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, new Object(), "Hello")); + + assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello", new Object())); + + assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, Object.class, String.class, "Hello", new Object())); + } + + @Test + public void testBuildSet() { + Set myset = Utils.buildSet("Hello", "World"); + assertNotNull(myset); + assertEquals(2, myset.size()); + } + @Test public void testIsJunitRunning() { assertTrue(Utils.isJUnitRunning()); } + public static class TestClass { + @MapValue("other_field") + private String field1; + + @MapValue(ignore = true) + private String field2; + + + private String field3; + + private final String field4 = "final"; + @MapValue + private int field5 = 5; + + private Boolean aBoolean = Boolean.valueOf("true"); + + private Double number = 1.0d; + + private String nullField = null; + + private TestClass testClass; + } + }