From 8ced44269d0a112c2809705c9106b2f29dce1524 Mon Sep 17 00:00:00 2001 From: John DeRegnaucourt Date: Sun, 12 Nov 2023 03:43:22 -0500 Subject: [PATCH] Added LRUCache and ClassUtilities. --- pom.xml | 8 +- .../cedarsoftware/util/ClassUtilities.java | 4 +- .../util/ClassUtilitiesTest.java | 155 ++++++++++++++++++ .../util/TestReflectionUtils.java | 107 +++++++++++- 4 files changed, 259 insertions(+), 15 deletions(-) create mode 100644 src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java diff --git a/pom.xml b/pom.xml index 501a28d9..f4f21b42 100644 --- a/pom.xml +++ b/pom.xml @@ -29,9 +29,9 @@ - 5.10.0 + 5.10.1 3.24.2 - 4.14.1 + 4.16.0 4.11.0 1.19.2 @@ -41,8 +41,8 @@ 3.1.0 3.11.0 - 3.6.0 - 3.2.1 + 3.6.2 + 3.2.2 3.3.0 1.26.4 5.1.9 diff --git a/src/main/java/com/cedarsoftware/util/ClassUtilities.java b/src/main/java/com/cedarsoftware/util/ClassUtilities.java index 0501de43..65985125 100644 --- a/src/main/java/com/cedarsoftware/util/ClassUtilities.java +++ b/src/main/java/com/cedarsoftware/util/ClassUtilities.java @@ -131,7 +131,7 @@ public static boolean isPrimitive(Class c) * Compare two primitives. * @return 0 if they are the same, -1 if not. Primitive wrapper classes are consider the same as primitive classes. */ - public static int comparePrimitiveToWrapper(Class source, Class destination) + private static int comparePrimitiveToWrapper(Class source, Class destination) { try { @@ -139,7 +139,7 @@ public static int comparePrimitiveToWrapper(Class source, Class destinatio } catch (Exception e) { - throw new RuntimeException("Error while attempting comparison of primitive types: " + source.getName() + " vs " + destination.getName(), e); + return -1; } } } diff --git a/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java b/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java new file mode 100644 index 00000000..6f5bdbb2 --- /dev/null +++ b/src/test/java/com/cedarsoftware/util/ClassUtilitiesTest.java @@ -0,0 +1,155 @@ +package com.cedarsoftware.util; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ClassUtilitiesTest { + // Example classes and interfaces for testing + interface TestInterface {} + interface SubInterface extends TestInterface {} + static class TestClass {} + static class SubClass extends TestClass implements TestInterface {} + static class AnotherClass {} + + @Test + void testComputeInheritanceDistanceWithNulls() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(null, null)); + assertEquals(-1, ClassUtilities.computeInheritanceDistance(String.class, null)); + assertEquals(-1, ClassUtilities.computeInheritanceDistance(null, Object.class)); + } + + @Test + void testComputeInheritanceDistanceWithSameClass() { + assertEquals(0, ClassUtilities.computeInheritanceDistance(String.class, String.class)); + assertEquals(0, ClassUtilities.computeInheritanceDistance(Object.class, Object.class)); + } + + @Test + void testComputeInheritanceDistanceWithSuperclass() { + assertEquals(1, ClassUtilities.computeInheritanceDistance(String.class, Object.class)); + assertEquals(1, ClassUtilities.computeInheritanceDistance(Integer.class, Number.class)); + } + + @Test + void testComputeInheritanceDistanceWithInterface() { + assertEquals(1, ClassUtilities.computeInheritanceDistance(ArrayList.class, List.class)); + assertEquals(2, ClassUtilities.computeInheritanceDistance(HashSet.class, Collection.class)); + } + + @Test + void testComputeInheritanceDistanceUnrelatedClasses() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(String.class, List.class)); + assertEquals(-1, ClassUtilities.computeInheritanceDistance(HashMap.class, List.class)); + } + + @Test + void testIsPrimitive() { + assertTrue(ClassUtilities.isPrimitive(int.class)); + assertTrue(ClassUtilities.isPrimitive(Integer.class)); + assertFalse(ClassUtilities.isPrimitive(String.class)); + } + + @Test + public void testClassToClassDirectInheritance() { + assertEquals(1, ClassUtilities.computeInheritanceDistance(SubClass.class, TestClass.class), + "Direct class to class inheritance should have a distance of 1."); + } + + @Test + public void testClassToClassNoInheritance() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(TestClass.class, AnotherClass.class), + "No inheritance between classes should return -1."); + } + + @Test + public void testClassToInterfaceDirectImplementation() { + assertEquals(1, ClassUtilities.computeInheritanceDistance(SubClass.class, TestInterface.class), + "Direct class to interface implementation should have a distance of 1."); + } + + @Test + public void testClassToInterfaceNoImplementation() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(TestClass.class, TestInterface.class), + "No implementation of the interface by the class should return -1."); + } + + @Test + public void testInterfaceToClass() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(TestInterface.class, TestClass.class), + "Interface to class should always return -1 as interfaces cannot inherit from classes."); + } + + @Test + public void testInterfaceToInterfaceDirectInheritance() { + assertEquals(1, ClassUtilities.computeInheritanceDistance(SubInterface.class, TestInterface.class), + "Direct interface to interface inheritance should have a distance of 1."); + } + + @Test + public void testInterfaceToInterfaceNoInheritance() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(TestInterface.class, SubInterface.class), + "No inheritance between interfaces should return -1."); + } + + @Test + public void testSameClass() { + assertEquals(0, ClassUtilities.computeInheritanceDistance(TestClass.class, TestClass.class), + "Distance from a class to itself should be 0."); + } + + @Test + public void testSameInterface() { + assertEquals(0, ClassUtilities.computeInheritanceDistance(TestInterface.class, TestInterface.class), + "Distance from an interface to itself should be 0."); + } + + @Test + public void testWithNullSource() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(null, TestClass.class), + "Should return -1 when source is null."); + } + + @Test + public void testWithNullDestination() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(TestClass.class, null), + "Should return -1 when destination is null."); + } + + @Test + public void testWithBothNull() { + assertEquals(-1, ClassUtilities.computeInheritanceDistance(null, null), + "Should return -1 when both source and destination are null."); + } + + @Test + public void testPrimitives() { + assert 0 == ClassUtilities.computeInheritanceDistance(byte.class, Byte.TYPE); + assert 0 == ClassUtilities.computeInheritanceDistance(Byte.TYPE, byte.class); + assert 0 == ClassUtilities.computeInheritanceDistance(Byte.TYPE, Byte.class); + assert 0 == ClassUtilities.computeInheritanceDistance(Byte.class, Byte.TYPE); + assert 0 == ClassUtilities.computeInheritanceDistance(Byte.class, byte.class); + assert 0 == ClassUtilities.computeInheritanceDistance(int.class, Integer.class); + assert 0 == ClassUtilities.computeInheritanceDistance(Integer.class, int.class); + + assert -1 == ClassUtilities.computeInheritanceDistance(Byte.class, int.class); + assert -1 == ClassUtilities.computeInheritanceDistance(int.class, Byte.class); + assert -1 == ClassUtilities.computeInheritanceDistance(int.class, String.class); + assert -1 == ClassUtilities.computeInheritanceDistance(int.class, String.class); + assert -1 == ClassUtilities.computeInheritanceDistance(Short.TYPE, Integer.TYPE); + assert -1 == ClassUtilities.computeInheritanceDistance(String.class, Integer.TYPE); + + assert -1 == ClassUtilities.computeInheritanceDistance(Date.class, java.sql.Date.class); + assert 1 == ClassUtilities.computeInheritanceDistance(java.sql.Date.class, Date.class); + } + +} diff --git a/src/test/java/com/cedarsoftware/util/TestReflectionUtils.java b/src/test/java/com/cedarsoftware/util/TestReflectionUtils.java index 63fdbc9c..6cadf7f0 100644 --- a/src/test/java/com/cedarsoftware/util/TestReflectionUtils.java +++ b/src/test/java/com/cedarsoftware/util/TestReflectionUtils.java @@ -3,21 +3,30 @@ import org.junit.jupiter.api.Test; import java.io.InputStream; -import java.lang.annotation.*; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author John DeRegnaucourt (jdereg@gmail.com) @@ -234,6 +243,8 @@ public void testGetClassName() throws Exception { assertEquals("null", ReflectionUtils.getClassName((Object)null)); assertEquals("java.lang.String", ReflectionUtils.getClassName("item")); + assertEquals("java.lang.String", ReflectionUtils.getClassName("")); + assertEquals("null", ReflectionUtils.getClassName(null)); } @Test @@ -663,4 +674,82 @@ private static URL[] getClasspathURLs() } } } + + + @Retention(RetentionPolicy.RUNTIME) + private @interface TestAnnotation {} + + @TestAnnotation + private static class AnnotatedTestClass { + @Override + public String toString() + { + return super.toString(); + } + } + + private static class TestClass { + private int field1; + public int field2; + } + + @Test + void testGetClassAnnotation() { + assertNotNull(ReflectionUtils.getClassAnnotation(AnnotatedTestClass.class, TestAnnotation.class)); + assertNull(ReflectionUtils.getClassAnnotation(TestClass.class, TestAnnotation.class)); + } + + @Test + void testGetMethodAnnotation() throws NoSuchMethodException { + Method method = AnnotatedTestClass.class.getDeclaredMethod("toString"); + assertNull(ReflectionUtils.getMethodAnnotation(method, TestAnnotation.class)); + } + + @Test + void testGetMethod() throws NoSuchMethodException { + Method method = ReflectionUtils.getMethod(TestClass.class, "toString"); + assertNotNull(method); + assertEquals("toString", method.getName()); + + assertNull(ReflectionUtils.getMethod(TestClass.class, "nonExistentMethod")); + } + + @Test + void testGetDeepDeclaredFields() { + Collection fields = ReflectionUtils.getDeepDeclaredFields(TestClass.class); + assertEquals(2, fields.size()); // field1 and field2 + } + + @Test + void testGetDeepDeclaredFieldMap() { + Map fieldMap = ReflectionUtils.getDeepDeclaredFieldMap(TestClass.class); + assertEquals(2, fieldMap.size()); + assertTrue(fieldMap.containsKey("field1")); + assertTrue(fieldMap.containsKey("field2")); + } + + @Test + void testCall() throws NoSuchMethodException { + TestClass testInstance = new TestClass(); + Method method = TestClass.class.getMethod("toString"); + String result = (String) ReflectionUtils.call(testInstance, method); + assertEquals(testInstance.toString(), result); + } + + @Test + void testCallWithArgs() throws NoSuchMethodException { + TestClass testInstance = new TestClass(); + String methodName = "equals"; + Object[] args = new Object[]{testInstance}; + Boolean result = (Boolean) ReflectionUtils.call(testInstance, methodName, args); + assertTrue(result); + } + + @Test + void testGetNonOverloadedMethod() { + Method method = ReflectionUtils.getNonOverloadedMethod(TestClass.class, "toString"); + assertNotNull(method); + assertEquals("toString", method.getName()); + } } +