From cd60fd0140dd764f80fea01060de2ca1de7531ca Mon Sep 17 00:00:00 2001 From: Voinea Radu Date: Fri, 6 Sep 2024 02:59:31 +0300 Subject: [PATCH] Added reflection testing --- build.gradle.kts | 2 + gradle/libs.versions.toml | 4 +- .../java/com.voinearadu/logger/Logger.java | 5 + .../reflections/Reflections.java | 99 +++++++++++++------ .../event_manager/EventManagerTests.java | 2 + .../file_manager/FileManagerTests.java | 2 + .../voinearadu/file_manager/GsonTests.java | 2 + .../lambda/LambdaRunnableExecutorTest.java | 3 +- .../com/voinearadu/logger/LoggerTest.java | 7 ++ .../message_builder/MessageBuilderTests.java | 7 ++ .../voinearadu/redis_manager/RedisTest.java | 2 + .../reflections/ReflectionsTest.java | 81 +++++++++++++++ .../annotation/TestAnnotation.java | 8 ++ .../voinearadu/reflections/dto/TestChild.java | 10 ++ .../reflections/dto/TestParent.java | 18 ++++ 15 files changed, 219 insertions(+), 33 deletions(-) create mode 100644 src/test/java/com/voinearadu/reflections/ReflectionsTest.java create mode 100644 src/test/java/com/voinearadu/reflections/annotation/TestAnnotation.java create mode 100644 src/test/java/com/voinearadu/reflections/dto/TestChild.java create mode 100644 src/test/java/com/voinearadu/reflections/dto/TestParent.java diff --git a/build.gradle.kts b/build.gradle.kts index d8cfb92..d3751ff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -40,6 +40,8 @@ dependencies { // Tests testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) + testImplementation(libs.slf4j.log4j) + testImplementation(libs.log4j) } tasks { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6eeb0fa..16b48f0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,10 +17,12 @@ jetbrains_annotations = { module = "org.jetbrains:annotations", version = "24.1. # Dependencies gson = { module = "com.google.code.gson:gson", version = "2.11.0" } jedis = { module = "redis.clients:jedis", version = "5.1.5" } -slf4j = { module = "org.slf4j:slf4j-api", version = "2.0.16" } apache_commons_compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" } apache_commons_lang3 = { module = "org.apache.commons:commons-lang3", version = "3.16.0" } apache_commons_pool2 = { module = "org.apache.commons:commons-pool2", version = "2.12.0" } apache_commons_io = { module = "commons-io:commons-io", version = "2.16.1" } +slf4j = { module = "org.slf4j:slf4j-api", version = "2.0.16" } +slf4j_log4j = { module = "org.slf4j:slf4j-log4j12", version = "2.0.16" } +log4j = { module = "org.apache.logging.log4j:log4j-core", version = "2.23.1" } diff --git a/src/main/java/com.voinearadu/logger/Logger.java b/src/main/java/com.voinearadu/logger/Logger.java index c0c669b..1596e3a 100644 --- a/src/main/java/com.voinearadu/logger/Logger.java +++ b/src/main/java/com.voinearadu/logger/Logger.java @@ -48,6 +48,11 @@ public static void debug(Object object) { log(Level.DEBUG, object, ConsoleColor.WHITE, 1); } + @SuppressWarnings("unused") + public static void debug(Object object, ConsoleColor color) { + log(Level.DEBUG, object, color, 1); + } + public static void good(Object object) { log(Level.INFO, object, ConsoleColor.GREEN, 1); } diff --git a/src/main/java/com.voinearadu/reflections/Reflections.java b/src/main/java/com.voinearadu/reflections/Reflections.java index 98c2089..59c4986 100644 --- a/src/main/java/com.voinearadu/reflections/Reflections.java +++ b/src/main/java/com.voinearadu/reflections/Reflections.java @@ -2,6 +2,7 @@ import com.voinearadu.logger.Logger; import lombok.Getter; +import org.apache.commons.io.FileUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,11 +22,23 @@ public class Reflections { private final List zipFiles; + private final List folders; private final ClassLoader classLoader; private final List searchDomain; - public Reflections(List zipFiles, ClassLoader classLoader, String... searchDomain) { + public Reflections(@NotNull List zipFiles, @NotNull List folders, @NotNull ClassLoader classLoader, @NotNull String... searchDomain) { this.zipFiles = zipFiles; + this.folders = folders; + + String[] classPathEntries = System.getProperty("java.class.path").split(File.pathSeparator); + for (String classPathEntry : classPathEntries) { + if (classPathEntry.endsWith(".jar") || classPathEntry.endsWith(".zip")) { + zipFiles.add(new File(classPathEntry)); + } else { + folders.add(new File(classPathEntry)); + } + } + this.classLoader = classLoader; this.searchDomain = Arrays.stream(searchDomain).map(domain -> { if (!domain.endsWith(".")) { @@ -35,7 +48,6 @@ public Reflections(List zipFiles, ClassLoader classLoader, String... searc }).toList(); } - @SuppressWarnings("unused") public static @Nullable Field getField(@NotNull Class clazz, String fieldName) { Field field = null; @@ -84,20 +96,24 @@ public Reflections(List zipFiles, ClassLoader classLoader, String... searc @SuppressWarnings("unused") public Reflections from(String... searchDomain) { - return new Reflections(zipFiles, classLoader, searchDomain); + return new Reflections(zipFiles, folders, classLoader, searchDomain); } public @NotNull Set> getClasses() { Set> classes = new HashSet<>(); for (File zipFile : zipFiles) { - classes.addAll(getClasses(zipFile)); + classes.addAll(getClassesFromZip(zipFile)); + } + + for (File zipFile : folders) { + classes.addAll(getClassesFromFolder(zipFile)); } return classes; } - private @NotNull Set> getClasses(File zipFile) { + private @NotNull Set> getClassesFromZip(File zipFile) { Set> classes = new HashSet<>(); try (ZipFile zip = new ZipFile(zipFile)) { @@ -106,39 +122,32 @@ public Reflections from(String... searchDomain) { while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); - if (entry == null) - break; - - if (entry.isDirectory()) { + if (entry == null || entry.isDirectory()) { continue; } - String name = entry.getName(); + Class clazz = processFile(entry.getName()); - if (!name.endsWith(".class")) { - continue; - } - - name = name.replace("/", "."); - name = name.replace(".class", ""); - - if (searchDomain.stream().noneMatch(name::startsWith)) { - continue; + if (clazz != null) { + classes.add(clazz); } + } + } catch (Exception error) { + Logger.error(error); + } - String simpleClassName = name.substring(name.lastIndexOf('.') + 1); + return classes; + } - // Skip Mixin classes - if (simpleClassName.contains("Mixin")) { - continue; - } + private @NotNull Set> getClassesFromFolder(File folder) { + Set> classes = new HashSet<>(); + try { + for (File file : FileUtils.listFiles(folder, new String[]{"class"}, true)) { + Class clazz = processFile(file.getAbsolutePath().replace(folder.getAbsolutePath() + File.separator, "")); - try { - classes.add(classLoader.loadClass(name)); - } catch (Throwable throwable) { - Logger.error("Failed to load class " + name + " from " + zipFile.getName()); - Logger.error(throwable); + if (clazz != null) { + classes.add(clazz); } } } catch (Exception error) { @@ -148,7 +157,36 @@ public Reflections from(String... searchDomain) { return classes; } - @SuppressWarnings("unused") + private @Nullable Class processFile(String fileName) { + if (!fileName.endsWith(".class")) { + return null; + } + + fileName = fileName.replace("/", "."); + fileName = fileName.replace("\\", "."); + fileName = fileName.replace(".class", ""); + + if (searchDomain.stream().noneMatch(fileName::startsWith)) { + return null; + } + + String simpleClassName = fileName.substring(fileName.lastIndexOf('.') + 1); + + // Skip Mixin classes + if (simpleClassName.contains("Mixin")) { + return null; + } + + try { + return classLoader.loadClass(fileName); + } catch (Throwable throwable) { + Logger.error("Failed to load class " + fileName + " from " + fileName); + Logger.error(throwable); + } + + return null; + } + public @NotNull Set> getTypesAnnotatedWith(@NotNull Class annotation) { Set> classes = new HashSet<>(); @@ -161,7 +199,6 @@ public Reflections from(String... searchDomain) { return classes; } - @SuppressWarnings("unused") public @NotNull Set getMethodsAnnotatedWith(@NotNull Class annotation) { Set methods = new HashSet<>(); diff --git a/src/test/java/com/voinearadu/event_manager/EventManagerTests.java b/src/test/java/com/voinearadu/event_manager/EventManagerTests.java index 35e96a2..3459b20 100644 --- a/src/test/java/com/voinearadu/event_manager/EventManagerTests.java +++ b/src/test/java/com/voinearadu/event_manager/EventManagerTests.java @@ -3,6 +3,7 @@ import com.voinearadu.event_manager.dto.TestComplexEvent; import com.voinearadu.event_manager.dto.TestEvent; import com.voinearadu.event_manager.manager.TestEventListener; +import org.apache.log4j.BasicConfigurator; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -17,6 +18,7 @@ public class EventManagerTests { @BeforeAll public static void setup() { + BasicConfigurator.configure(); eventManager.register(new TestEventListener()); } diff --git a/src/test/java/com/voinearadu/file_manager/FileManagerTests.java b/src/test/java/com/voinearadu/file_manager/FileManagerTests.java index 7f791e4..cbc2605 100644 --- a/src/test/java/com/voinearadu/file_manager/FileManagerTests.java +++ b/src/test/java/com/voinearadu/file_manager/FileManagerTests.java @@ -4,6 +4,7 @@ import com.google.gson.GsonBuilder; import com.voinearadu.file_manager.dto.files.FileObject; import com.voinearadu.file_manager.manager.FileManager; +import org.apache.log4j.BasicConfigurator; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -20,6 +21,7 @@ public class FileManagerTests { @BeforeAll public static void init() { + BasicConfigurator.configure(); Gson gson = new GsonBuilder() //NOPMD - suppressed GsonCreatedForEachMethodCall .create(); fileManager = new FileManager(() -> gson, "tmp"); diff --git a/src/test/java/com/voinearadu/file_manager/GsonTests.java b/src/test/java/com/voinearadu/file_manager/GsonTests.java index 70254b6..6b40ce4 100644 --- a/src/test/java/com/voinearadu/file_manager/GsonTests.java +++ b/src/test/java/com/voinearadu/file_manager/GsonTests.java @@ -13,6 +13,7 @@ import com.voinearadu.file_manager.dto.serializable.SerializableMap; import com.voinearadu.file_manager.dto.serializable.SerializableObject; import lombok.Getter; +import org.apache.log4j.BasicConfigurator; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -32,6 +33,7 @@ public class GsonTests { @BeforeAll public static void init() { + BasicConfigurator.configure(); ClassLoader classLoader = GsonTests.class.getClassLoader(); SerializableListGsonTypeAdapter serializableListGsonTypeAdapter = new SerializableListGsonTypeAdapter(classLoader); diff --git a/src/test/java/com/voinearadu/lambda/LambdaRunnableExecutorTest.java b/src/test/java/com/voinearadu/lambda/LambdaRunnableExecutorTest.java index 7c2b446..6aaa3ae 100644 --- a/src/test/java/com/voinearadu/lambda/LambdaRunnableExecutorTest.java +++ b/src/test/java/com/voinearadu/lambda/LambdaRunnableExecutorTest.java @@ -2,6 +2,7 @@ import com.voinearadu.lambda.lambda.*; import lombok.SneakyThrows; +import org.apache.log4j.BasicConfigurator; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -17,8 +18,8 @@ public class LambdaRunnableExecutorTest { @BeforeAll public static void init() { + BasicConfigurator.configure(); } - @Test public void testLambdaExecutors() { ArgLambdaExecutor> addEmpty = (list) -> list.add("empty"); diff --git a/src/test/java/com/voinearadu/logger/LoggerTest.java b/src/test/java/com/voinearadu/logger/LoggerTest.java index 034559c..90b378e 100644 --- a/src/test/java/com/voinearadu/logger/LoggerTest.java +++ b/src/test/java/com/voinearadu/logger/LoggerTest.java @@ -1,6 +1,8 @@ package com.voinearadu.logger; import lombok.SneakyThrows; +import org.apache.log4j.BasicConfigurator; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; @@ -14,6 +16,11 @@ @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class LoggerTest { + @BeforeAll + public static void init() { + BasicConfigurator.configure(); + } + @SneakyThrows @Test public void testDebugLogger() { diff --git a/src/test/java/com/voinearadu/message_builder/MessageBuilderTests.java b/src/test/java/com/voinearadu/message_builder/MessageBuilderTests.java index d50fe20..82766f8 100644 --- a/src/test/java/com/voinearadu/message_builder/MessageBuilderTests.java +++ b/src/test/java/com/voinearadu/message_builder/MessageBuilderTests.java @@ -1,6 +1,8 @@ package com.voinearadu.message_builder; +import org.apache.log4j.BasicConfigurator; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -11,6 +13,11 @@ public class MessageBuilderTests { + @BeforeAll + public static void init() { + BasicConfigurator.configure(); + } + @Test public void testMessageBuilder() { MessageBuilder builder1 = new MessageBuilder("This is a %placeholder%"); diff --git a/src/test/java/com/voinearadu/redis_manager/RedisTest.java b/src/test/java/com/voinearadu/redis_manager/RedisTest.java index b1674fb..08858bb 100644 --- a/src/test/java/com/voinearadu/redis_manager/RedisTest.java +++ b/src/test/java/com/voinearadu/redis_manager/RedisTest.java @@ -17,6 +17,7 @@ import com.voinearadu.redis_manager.manager.RedisManager; import com.voinearadu.redis_manager.manager.TestListener; import lombok.Getter; +import org.apache.log4j.BasicConfigurator; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -32,6 +33,7 @@ public class RedisTest { @BeforeAll public static void init() { + BasicConfigurator.configure(); MessageBuilderManager.init(false); ClassLoader classLoader = RedisTest.class.getClassLoader(); diff --git a/src/test/java/com/voinearadu/reflections/ReflectionsTest.java b/src/test/java/com/voinearadu/reflections/ReflectionsTest.java new file mode 100644 index 0000000..69c024b --- /dev/null +++ b/src/test/java/com/voinearadu/reflections/ReflectionsTest.java @@ -0,0 +1,81 @@ +package com.voinearadu.reflections; + +import com.voinearadu.reflections.annotation.TestAnnotation; +import com.voinearadu.reflections.dto.TestChild; +import com.voinearadu.reflections.dto.TestParent; +import org.apache.log4j.BasicConfigurator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ReflectionsTest { + + private static Reflections reflections; + + @BeforeAll + public static void init() { + BasicConfigurator.configure(); + + ReflectionsTest.reflections = new Reflections(new ArrayList<>(), new ArrayList<>(), ReflectionsTest.class.getClassLoader(), "com.voinearadu.reflections"); + } + + @Test + public void testTypeAnnotationProcessing() { + int typesCount = reflections.getTypesAnnotatedWith(TestAnnotation.class).size(); + + assertEquals(1, typesCount); + } + + @Test + public void testMethodAnnotationProcessing() { + int typesCount = reflections.getMethodsAnnotatedWith(TestAnnotation.class).size(); + + assertEquals(1, typesCount); + } + + @Test + public void testGetCallingMethod() { + Method method = Reflections.getCallingMethod(1); + + assertNotNull(method); + assertEquals("testGetCallingMethod", method.getName()); + } + + + @Test + public void testTypeChildrenProcessing() { + int typesCount = reflections.getOfType(TestParent.class).size(); + + assertEquals(2, typesCount); + } + + @Test + public void testGetField() { + int childFieldsCount = Reflections.getFields(TestChild.class).size(); + Field publicChildFiled = Reflections.getField(TestChild.class, "publicChildFiled"); + Field protectedChildField = Reflections.getField(TestChild.class, "protectedChildField"); + Field privateChildField = Reflections.getField(TestChild.class, "privateChildField"); + + int parentFieldsCount = Reflections.getFields(TestParent.class).size(); + Field publicParentField = Reflections.getField(TestParent.class, "publicParentField"); + Field protectedParentField = Reflections.getField(TestParent.class, "protectedParentField"); + Field privateParentField = Reflections.getField(TestParent.class, "privateParentField"); + + assertEquals(6, childFieldsCount); + assertNotNull(publicChildFiled); + assertNotNull(protectedChildField); + assertNotNull(privateChildField); + + assertEquals(3, parentFieldsCount); + assertNotNull(publicParentField); + assertNotNull(protectedParentField); + assertNotNull(privateParentField); + } + +} diff --git a/src/test/java/com/voinearadu/reflections/annotation/TestAnnotation.java b/src/test/java/com/voinearadu/reflections/annotation/TestAnnotation.java new file mode 100644 index 0000000..80f209a --- /dev/null +++ b/src/test/java/com/voinearadu/reflections/annotation/TestAnnotation.java @@ -0,0 +1,8 @@ +package com.voinearadu.reflections.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface TestAnnotation { +} diff --git a/src/test/java/com/voinearadu/reflections/dto/TestChild.java b/src/test/java/com/voinearadu/reflections/dto/TestChild.java new file mode 100644 index 0000000..b7e624d --- /dev/null +++ b/src/test/java/com/voinearadu/reflections/dto/TestChild.java @@ -0,0 +1,10 @@ +package com.voinearadu.reflections.dto; + +@SuppressWarnings("unused") +public class TestChild extends TestParent { + + public int publicChildFiled; + protected int protectedChildField; + private int privateChildField; + +} diff --git a/src/test/java/com/voinearadu/reflections/dto/TestParent.java b/src/test/java/com/voinearadu/reflections/dto/TestParent.java new file mode 100644 index 0000000..dc75933 --- /dev/null +++ b/src/test/java/com/voinearadu/reflections/dto/TestParent.java @@ -0,0 +1,18 @@ +package com.voinearadu.reflections.dto; + +import com.voinearadu.reflections.annotation.TestAnnotation; + +@SuppressWarnings("unused") +@TestAnnotation +public class TestParent { + + public int publicParentField; + protected int protectedParentField; + private int privateParentField; + + @TestAnnotation + public void testMethod() { + + } + +}