📜 ⬆️ ⬇️

Tools for searching annotated classes in Java

The article provides a small overview of the three tools for searching annotated classes in a java project.


image


Training cats
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {} @MyAnnotation public class Bar {} @MyAnnotation public class Foo {} 

Spring


In Spring, ClassPathScanningCandidateComponentProvider serves for this purpose.


Feature: climbs into ClassPath, looking for classes that meet specified conditions

Additional features

has many other filters (for type, for methods, etc.)


Example


 @Benchmark public void spring() { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class)); List<String> collect = scanner .findCandidateComponents("edu.pqdn.scanner") .stream() .map(BeanDefinition::getBeanClassName) .filter(Objects::nonNull) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); } 

Reflections


Feature: climbs into ClassPath, looking for classes that meet specified conditions

Additional features
  • get all subtypes of some type
  • get all types / members annotated with some annotation
  • get all resources matching a regular expression
  • parameters, parameter returns and return type

dependency
 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.11</version> </dependency> 

Example


 @Benchmark public void reflection() { Reflections reflections = new Reflections("edu.pqdn.scanner"); Set<Class<?>> set = reflections.getTypesAnnotatedWith(MyAnnotation.class); List<String> collect = set.stream() .map(Class::getCanonicalName) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); } 

classindex


Feature: Does not climb in ClassPath, instead of this classes are indexed at the compilation stage

dependency
 <dependency> <groupId>org.atteo.classindex</groupId> <artifactId>classindex</artifactId> <version>3.4</version> </dependency> 

Training cats
 @IndexMyAnnotated public @interface IndexerAnnotation {} @IndexerMyAnnotation public class Bar {} @IndexerMyAnnotation public class Foo {} 

Example


 @Benchmark public void indexer() { Iterable<Class<?>> iterable = ClassIndex.getAnnotated(IndexerMyAnnotation.class); List<String> list = StreamSupport.stream(iterable.spliterator(), false) .map(aClass -> aClass.getCanonicalName()) .collect(Collectors.toList()); assertEquals(list.size(), 2); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Bar")); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Foo")); } 

Jmh


 Benchmark Mode Cnt Score Error Units ScannerBenchmark.indexer avgt 50 0,100 ? 0,001 ms/op ScannerBenchmark.reflection avgt 50 5,157 ? 0,047 ms/op ScannerBenchmark.spring avgt 50 4,706 ? 0,294 ms/op 

Conclusion


As you can see, the indexer is the most productive tool, however, the annotations for which the search is performed must have the stereotype @IndexAnnotated.


The other two tools are working much slower, but for their work no shamanism with code is needed. The disadvantage is completely leveled out if the search is needed only at the start of the application.


')

Source: https://habr.com/ru/post/424511/


All Articles