diff --git a/spring-boot-modules/spring-boot-libraries-2/pom.xml b/spring-boot-modules/spring-boot-libraries-2/pom.xml index f62a341efc..79c090dde5 100644 --- a/spring-boot-modules/spring-boot-libraries-2/pom.xml +++ b/spring-boot-modules/spring-boot-libraries-2/pom.xml @@ -62,6 +62,16 @@ spqr 0.11.2 + + org.reflections + reflections + 0.10.2 + + + org.jboss + jandex + 2.4.3.Final + @@ -92,6 +102,27 @@ + + org.jboss.jandex + jandex-maven-plugin + 1.2.3 + + + compile + make-index + + jandex + + + + + ${project.build.outputDirectory} + + + + + + diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java new file mode 100644 index 0000000000..64849d6a3a --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotatedClass.java @@ -0,0 +1,14 @@ +package com.baeldung.annotation.scanner; + +@SampleAnnotation(name = "SampleAnnotatedClass") +public class SampleAnnotatedClass { + + @SampleAnnotation(name = "annotatedMethod") + public void annotatedMethod() { + //Do something + } + + public void notAnnotatedMethod() { + //Do something + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java new file mode 100644 index 0000000000..212e12e910 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotation.java @@ -0,0 +1,14 @@ +package com.baeldung.annotation.scanner; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target({ METHOD, TYPE }) +@Retention(RUNTIME) +public @interface SampleAnnotation { + String name(); +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java new file mode 100644 index 0000000000..5cc9a2e8b3 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/SampleAnnotationScanner.java @@ -0,0 +1,13 @@ +package com.baeldung.annotation.scanner; + +import java.util.List; + +public interface SampleAnnotationScanner { + List scanAnnotatedMethods(); + + List scanAnnotatedClasses(); + + boolean supportsMethodScan(); + + boolean supportsClassScan(); +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java new file mode 100644 index 0000000000..1566dc3fad --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/ScanNotSupportedException.java @@ -0,0 +1,4 @@ +package com.baeldung.annotation.scanner; + +public class ScanNotSupportedException extends RuntimeException{ +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java new file mode 100644 index 0000000000..bd7c129bfd --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/UnexpectedScanException.java @@ -0,0 +1,7 @@ +package com.baeldung.annotation.scanner; + +public class UnexpectedScanException extends RuntimeException { + public UnexpectedScanException(Throwable ex) { + super(ex); + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java new file mode 100644 index 0000000000..fc10db223e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/jandexlib/JandexScannerService.java @@ -0,0 +1,76 @@ +package com.baeldung.annotation.scanner.jandexlib; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Index; +import org.jboss.jandex.IndexReader; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.UnexpectedScanException; + +@Service +public class JandexScannerService implements SampleAnnotationScanner { + @Value("classpath:META-INF/jandex.idx") + private Resource appFile; + + @Override + public List scanAnnotatedMethods() { + try { + final IndexReader reader = new IndexReader(appFile.getInputStream()); + Index jandexFile = reader.read(); + final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + List annotatedMethods = new ArrayList<>(); + for (AnnotationInstance annotationInstance : appAnnotationList) { + if (annotationInstance.target() + .kind() == AnnotationTarget.Kind.METHOD) { + annotatedMethods.add(annotationInstance.value("name") + .value() + .toString()); + } + } + return Collections.unmodifiableList(annotatedMethods); + } catch (IOException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public List scanAnnotatedClasses() { + try { + final IndexReader reader = new IndexReader(appFile.getInputStream()); + Index jandexFile = reader.read(); + final List appAnnotationList = jandexFile.getAnnotations(DotName.createSimple("com.baeldung.annotation.scanner.SampleAnnotation")); + List annotatedClasses = new ArrayList<>(); + for (AnnotationInstance annotationInstance : appAnnotationList) { + if (annotationInstance.target() + .kind() == AnnotationTarget.Kind.CLASS) { + annotatedClasses.add(annotationInstance.value("name") + .value() + .toString()); + } + } + return Collections.unmodifiableList(annotatedClasses); + } catch (IOException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java new file mode 100644 index 0000000000..2833bb1326 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/javareflectionlib/JavaReflectionsScannerService.java @@ -0,0 +1,58 @@ +package com.baeldung.annotation.scanner.javareflectionlib; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.UnexpectedScanException; + +@Service +public class JavaReflectionsScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + try { + Class clazz = ClassLoader.getSystemClassLoader() + .loadClass("com.baeldung.annotation.scanner.SampleAnnotatedClass"); + Method[] methods = clazz.getMethods(); + List annotatedMethods = new ArrayList<>(); + for (Method method : methods) { + SampleAnnotation annotation = method.getAnnotation(SampleAnnotation.class); + if (annotation != null) { + annotatedMethods.add(annotation.name()); + } + } + return Collections.unmodifiableList(annotatedMethods); + } catch (ClassNotFoundException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public List scanAnnotatedClasses() { + try { + Class clazz = ClassLoader.getSystemClassLoader() + .loadClass("com.baeldung.annotation.scanner.SampleAnnotatedClass"); + SampleAnnotation classAnnotation = clazz.getAnnotation(SampleAnnotation.class); + List annotatedClasses = new ArrayList<>(); + annotatedClasses.add(classAnnotation.name()); + return Collections.unmodifiableList(annotatedClasses); + } catch (ClassNotFoundException e) { + throw new UnexpectedScanException(e); + } + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java new file mode 100644 index 0000000000..82a10e21aa --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/reflectionslib/ReflectionsScannerService.java @@ -0,0 +1,45 @@ +package com.baeldung.annotation.scanner.reflectionslib; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.reflections.Reflections; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; + +@Service +public class ReflectionsScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); + Set methods = reflections.getMethodsAnnotatedWith(SampleAnnotation.class); + return methods.stream() + .map(method -> method.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public List scanAnnotatedClasses() { + Reflections reflections = new Reflections("com.baeldung.annotation.scanner"); + Set> types = reflections.getTypesAnnotatedWith(SampleAnnotation.class); + return types.stream() + .map(clazz -> clazz.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java new file mode 100644 index 0000000000..cd31ae686e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcontextlib/SpringBeanAnnotationScannerService.java @@ -0,0 +1,52 @@ +package com.baeldung.annotation.scanner.springcontextlib; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Service; + +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.ScanNotSupportedException; + +@Service +public class SpringBeanAnnotationScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + throw new ScanNotSupportedException(); + } + + @Override + public List scanAnnotatedClasses() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(SampleAnnotation.class)); + Set beanDefs = provider.findCandidateComponents("com.baeldung.annotation.scanner"); + List annotatedBeans = new ArrayList<>(); + for (BeanDefinition bd : beanDefs) { + if (bd instanceof AnnotatedBeanDefinition) { + Map annotAttributeMap = ((AnnotatedBeanDefinition) bd).getMetadata() + .getAnnotationAttributes(SampleAnnotation.class.getCanonicalName()); + annotatedBeans.add(annotAttributeMap.get("name") + .toString()); + } + } + return Collections.unmodifiableList(annotatedBeans); + } + + @Override + public boolean supportsMethodScan() { + return false; + } + + @Override + public boolean supportsClassScan() { + return true; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java new file mode 100644 index 0000000000..f3421fe46d --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/annotation/scanner/springcorelib/SpringCoreAnnotationScannerService.java @@ -0,0 +1,42 @@ +package com.baeldung.annotation.scanner.springcorelib; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.ClassUtils; + +import com.baeldung.annotation.scanner.SampleAnnotationScanner; +import com.baeldung.annotation.scanner.SampleAnnotatedClass; +import com.baeldung.annotation.scanner.SampleAnnotation; +import com.baeldung.annotation.scanner.ScanNotSupportedException; + +@Service +public class SpringCoreAnnotationScannerService implements SampleAnnotationScanner { + @Override + public List scanAnnotatedMethods() { + final Class userClass = ClassUtils.getUserClass(SampleAnnotatedClass.class); + return Arrays.stream(userClass.getMethods()) + .filter(method -> AnnotationUtils.getAnnotation(method, SampleAnnotation.class) != null) + .map(method -> method.getAnnotation(SampleAnnotation.class) + .name()) + .collect(Collectors.toList()); + } + + @Override + public List scanAnnotatedClasses() { + throw new ScanNotSupportedException(); + } + + @Override + public boolean supportsMethodScan() { + return true; + } + + @Override + public boolean supportsClassScan() { + return false; + } +} diff --git a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java new file mode 100644 index 0000000000..80eca2b4c5 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/annotation/scanner/SampleAnnotationScannerUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.annotation.scanner; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SampleAnnotationScannerUnitTest { + @Autowired + private List scannerList; + + @Test + public void givenPackage_whenScanAnnotatedClasses_thenAnnotationValues() { + final List annotatedClasses = scannerList.stream() + .filter(SampleAnnotationScanner::supportsClassScan) + .map(SampleAnnotationScanner::scanAnnotatedClasses) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertNotNull(annotatedClasses); + assertEquals(4, annotatedClasses.size()); + annotatedClasses.forEach(annotValue -> assertEquals("SampleAnnotatedClass", annotValue)); + } + + @Test + public void givenPackage_whenScanAnnotatedMethods_thenAnnotationValues() { + final List annotatedMethods = scannerList.stream() + .filter(SampleAnnotationScanner::supportsMethodScan) + .map(SampleAnnotationScanner::scanAnnotatedMethods) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertNotNull(annotatedMethods); + assertEquals(3, annotatedMethods.size()); + annotatedMethods.forEach(annotValue -> assertEquals("annotatedMethod", annotValue)); + } + +}