Im trying to make a generic instance mapper from an SQLite DB to my project logic layer.
Each entry in the mapper is an instance of some class "DAL< name >" for example DALProduct all in the same package that extends class DALObject with the following structure:
public abstract class DALObject{
abstract String getCreate();
... //other logic
}
Using reflection I can easily call the getCreate method on each class and get what I need from it.
The issue is that I don't know how many child classes DALObject will have and i want a mapper that won't need to be touched when a new one is added.
I know that you can get all child classes of DALObjects that have been loaded but I run this code at the very start of my program before I load any of the classes.
Any ideas? I have a pretty big constraint case so maybe I can somehow hack it together.
Such task is only possible by scanning every class on the classpath (which, depending on how many libraries you use, are usually a lot) and see if it extends DALObject.
If you want to go that route, the org.reflections library can help you with that:
Reflections reflections = new Reflections("my.package",
Reflector.class.getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Module>> modules = reflections.getSubTypesOf(DALObject.class);
For performance reasons, I highly recommend doing this scan once during startup of your application and store the results.
As an alternative approach (I did not bother with generic type safety of Class here, this is to be implemented):
public abstract class DALObject {
public static List<Class> subTypes = new ArrayList<>();
public DALObject() {
DALObject.subTypes.add(this.getClass());
}
}
Obviously this only works if you instantiate objects of the subclasses somewhere, if your getCreate is meant to do that in the first place, my suggestion will obviously not work.
This would be a perfect instance of when to use an annotation. You could define the annotation before the declaration of each class, indicating that the class has some meta-data about 'DALObjects'. Then you could use Reflections or some similar library to easily find all Class objects with this annotation.
For example;
#Target(value=TYPE)
public #interface DALObject {
}
#DALObject
public class MyDALObject {
}
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new TypeAnnotationsScanner()));
Set<Class<?>> annotatedWithDALObject = reflections.getTypesAnnotatedWith(DALObject.class);
Last I know, Reflections isn't well supported (only minor changes in years) and still doesn't work with modules.
Instead, I'd recommend using ClassGraph, which is ultra-actively maintained, and works with modules, weird class loaders and what not.
You'd find DALObject implementations like this:
ScanResult scanResults = new ClassGraph()
.acceptPackages(packages) //skip to scan ALL packages
.enableAllInfo() //Not necessary but gives you more info to filter on, if needed
.initializeLoadedClasses()
.scan();
//You can cache, or serialize scanResults using scanResults.toJSON()
List<Class<?>> impls = scanResults.getAllClasses().stream()
.filter(impl -> impl.extendsSuperclass(DALObject.getName()))
// or impl.implementsInterface(DALObject.getName()) if DALObject is an interface
.flatMap(info -> info.loadClass()) //or load the class yourself if you need to customize the logic
.collect(Collectors.toList());
Related
How do I search the whole classpath for an annotated class?
I'm doing a library and I want to allow the users to annotate their classes, so when the Web application starts I need to scan the whole classpath for certain annotation.
I'm thinking about something like the new functionality for Java EE 5 Web Services or EJB's. You annotate your class with #WebService or #EJB and the system finds these classes while loading so they are accessible remotely.
Use org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
API
A component provider that scans the classpath from a base package. It then applies exclude and include filters to the resulting classes to find candidates.
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);
scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));
for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
System.out.println(bd.getBeanClassName());
And another solution is ronmamo's Reflections.
Quick review:
Spring solution is the way to go if you're using Spring. Otherwise it's a big dependency.
Using ASM directly is a bit cumbersome.
Using Java Assist directly is clunky too.
Annovention is super lightweight and convenient. No maven integration yet.
Reflections indexes everything and then is super fast.
You can find classes with any given annotation with ClassGraph, as well as searching for other criteria of interest, e.g. classes that implement a given interface. (Disclaimer, I am the author of ClassGraph.) ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in whitelisted packages, and you can query that class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
If you want a really light weight (no dependencies, simple API, 15 kb jar file) and very fast solution, take a look at annotation-detector found at https://github.com/rmuller/infomas-asl
Disclaimer: I am the author.
You can use Java Pluggable Annotation Processing API to write annotation processor which will be executed during the compilation process and will collect all annotated classes and build the index file for runtime use.
This is the fastest way possible to do annotated class discovery because you don't need to scan your classpath at runtime, which is usually very slow operation. Also this approach works with any classloader and not only with URLClassLoaders usually supported by runtime scanners.
The above mechanism is already implemented in ClassIndex library.
To use it annotate your custom annotation with #IndexAnnotated meta-annotation. This will create at compile time an index file: META-INF/annotations/com/test/YourCustomAnnotation listing all annotated classes. You can acccess the index at runtime by executing:
ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
There's a wonderful comment by zapp that sinks in all those answers:
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)
Spring has something called a AnnotatedTypeScanner class.
This class internally uses
ClassPathScanningCandidateComponentProvider
This class has the code for actual scanning of the classpath resources. It does this by using the class metadata available at runtime.
One can simply extend this class or use the same class for scanning. Below is the constructor definition.
/**
* Creates a new {#link AnnotatedTypeScanner} for the given annotation types.
*
* #param considerInterfaces whether to consider interfaces as well.
* #param annotationTypes the annotations to scan for.
*/
public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {
this.annotationTypess = Arrays.asList(annotationTypes);
this.considerInterfaces = considerInterfaces;
}
Is it too late to answer.
I would say, its better to go by Libraries like ClassPathScanningCandidateComponentProvider or like Scannotations
But even after somebody wants to try some hands on it with classLoader, I have written some on my own to print the annotations from classes in a package:
public class ElementScanner {
public void scanElements(){
try {
//Get the package name from configuration file
String packageName = readConfig();
//Load the classLoader which loads this class.
ClassLoader classLoader = getClass().getClassLoader();
//Change the package structure to directory structure
String packagePath = packageName.replace('.', '/');
URL urls = classLoader.getResource(packagePath);
//Get all the class files in the specified URL Path.
File folder = new File(urls.getPath());
File[] classes = folder.listFiles();
int size = classes.length;
List<Class<?>> classList = new ArrayList<Class<?>>();
for(int i=0;i<size;i++){
int index = classes[i].getName().indexOf(".");
String className = classes[i].getName().substring(0, index);
String classNamePath = packageName+"."+className;
Class<?> repoClass;
repoClass = Class.forName(classNamePath);
Annotation[] annotations = repoClass.getAnnotations();
for(int j =0;j<annotations.length;j++){
System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
}
classList.add(repoClass);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* Unmarshall the configuration file
* #return
*/
public String readConfig(){
try{
URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
Unmarshaller um = jContext.createUnmarshaller();
RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
return rc.getRepository().getPackageName();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
And in config File, you put the package name and unmarshall it to a class .
The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).
So, even if you could enumerate all classes, this would be very time- and memory-consuming.
The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.
With Spring you can also just write the following using AnnotationUtils class. i.e.:
Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);
For more details and all different methods check official docs:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html
If you're looking for an alternative to reflections I'd like to recommend Panda Utilities - AnnotationsScanner. It's a Guava-free (Guava has ~3MB, Panda Utilities has ~200kb) scanner based on the reflections library source code.
It's also dedicated for future-based searches. If you'd like to scan multiple times included sources or even provide an API, which allows someone scanning current classpath, AnnotationsScannerProcess caches all fetched ClassFiles, so it's really fast.
Simple example of AnnotationsScanner usage:
AnnotationsScanner scanner = AnnotationsScanner.createScanner()
.includeSources(ExampleApplication.class)
.build();
AnnotationsScannerProcess process = scanner.createWorker()
.addDefaultProjectFilters("net.dzikoysk")
.fetch();
Set<Class<?>> classes = process.createSelector()
.selectTypesAnnotatedWith(AnnotationTest.class);
Google Reflection if you want to discover interfaces as well.
Spring ClassPathScanningCandidateComponentProvider is not discovering interfaces.
Google Reflections seems to be much faster than Spring. Found this feature request that adresses this difference: http://www.opensaga.org/jira/browse/OS-738
This is a reason to use Reflections as startup time of my application is really important during development. Reflections seems also to be very easy to use for my use case (find all implementers of an interface).
Can I do it with reflection or something like that?
I have been searching for a while and there seems to be different approaches, here is a summary:
reflections library is pretty popular if u don't mind adding the dependency. It would look like this:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (as per erickson answer) and it would look like this:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
Note that for this to work you need to define Petas a ServiceProviderInterface (SPI) and declare its implementations. you do that by creating a file in resources/META-INF/services with the name examples.reflections.Pet and declare all implementations of Pet in it
examples.reflections.Dog
examples.reflections.Cat
package-level annotation. here is an example:
Package[] packages = Package.getPackages();
for (Package p : packages) {
MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
if (annotation != null) {
Class<?>[] implementations = annotation.implementationsOfPet();
for (Class<?> impl : implementations) {
System.out.println(impl.getSimpleName());
}
}
}
and the annotation definition:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PACKAGE)
public #interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
and you must declare the package-level annotation in a file named package-info.java inside that package. here are sample contents:
#MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
Note that only packages that are known to the ClassLoader at that time will be loaded by a call to Package.getPackages().
In addition, there are other approaches based on URLClassLoader that will always be limited to classes that have been already loaded, Unless you do a directory-based search.
What erickson said, but if you still want to do it then take a look at Reflections. From their page:
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
In general, it's expensive to do this. To use reflection, the class has to be loaded. If you want to load every class available on the classpath, that will take time and memory, and isn't recommended.
If you want to avoid this, you'd need to implement your own class file parser that operated more efficiently, instead of reflection. A byte code engineering library may help with this approach.
The Service Provider mechanism is the conventional means to enumerate implementations of a pluggable service, and has become more established with the introduction of Project Jigsaw (modules) in Java 9. Use the ServiceLoader in Java 6, or implement your own in earlier versions. I provided an example in another answer.
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired
private List<ITask> tasks;
}
The most robust mechanism for listing all classes that implement a given interface is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
.enableClassInfo().scan()) {
for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
foundImplementingClass(ci); // Do something with the ClassInfo object
}
}
With ClassGraph it's pretty simple:
Groovy code to find implementations of my.package.MyInterface:
#Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}
What erikson said is best. Here's a related question and answer thread - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
The Apache BCEL library allows you to read classes without loading them. I believe it will be faster because you should be able to skip the verification step. The other problem with loading all classes using the classloader is that you will suffer a huge memory impact as well as inadvertently run any static code blocks which you probably do not want to do.
The Apache BCEL library link - http://jakarta.apache.org/bcel/
Yes, the first step is to identify "all" the classes that you cared about. If you already have this information, you can enumerate through each of them and use instanceof to validate the relationship. A related article is here: https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html
Also, if you are writing an IDE plugin (where what you are trying to do is relatively common), then the IDE typically offers you more efficient ways to access the class hierarchy of the current state of the user code.
I ran into the same issue. My solution was to use reflection to examine all of the methods in an ObjectFactory class, eliminating those that were not createXXX() methods returning an instance of one of my bound POJOs. Each class so discovered is added to a Class[] array, which was then passed to the JAXBContext instantiation call. This performs well, needing only to load the ObjectFactory class, which was about to be needed anyway. I only need to maintain the ObjectFactory class, a task either performed by hand (in my case, because I started with POJOs and used schemagen), or can be generated as needed by xjc. Either way, it is performant, simple, and effective.
A new version of #kaybee99's answer, but now returning what the user asks: the implementations...
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}
I'm a huge fan of Java's annotations, but find it a pain in the neck to have to include Google's Reflections or Scannotations every time I want to make my own.
I haven't been able to find any documentation about Java being able to automatically scan for annotations & use them appropriately, without the help of a container or alike.
Question: Have I missed something fundamental about Java, or were annotations always designed such that manual scanning & checking is required? Is there some built-in way of handling annotations?
To clarify further
I'd like to be able to approach annotations in Java a little more programatically. For instance, say you wanted to build a List of Cars. To do this, you annotate the list with a class that can populate the list for you. For instance:
#CarMaker
List<Car> cars = new List<Car>();
In this example, the CarMaker annotation is approached by Java, who strikes a deal and asks them how many cars they want to provide. It's up to the CarMaker annotation/class to then provide them with a list of which cars to include. This could be all classes with #CarType annotations, and a Car interface.
Another way of looking at it, is that if you know you want to build something like this: List<Car> cars, you could annotate it with #ListMaker<Car>. The ListMaker is something built into Java. It looks for all classes annotated with #CarType, and populates the list accordingly.
You can create your own annotations and apply them to your own classes.
If you specify that an annotation is detectable at runtime, you can process it easily with reflection.
For example, you could use something like this to print the name of each field in a class that has been marked with the Funky annotation:
for (Field someField : AnnotatedClass.getClass().getDeclaredFields()) {
if (someField.isAnnotationPresent(Funky.class)) {
System.out.println("This field is funky: " + someField.getName());
}
}
The code to declare the Funky annotation would look something like this:
package org.foo.annotations;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Funky { }
Here's a class that uses the annotation:
package org.foo.examples;
import org.foo.annotations.Funky;
public class AnnotatedClass {
#Funky
private String funkyString;
private String nonFunkyString;
#Funky
private Integer funkyInteger;
private Integer nonFunkyInteger;
}
Here's some more reading on Annotations.
Here are the javadocs for the classes used above:
Retention annotation
RetentionPolicy enum
Target annotation
Field class
isAnnotationPresent() method
getDeclaredFields() method
I'm trying to understand your car example, but I'm not sure I follow what you want.
If you had a list of objects (Jaguar, Porche, Ferrari, Kia) that extend Car and are marked with various car-related annotations, you could create an object that filters the list based on annotations.
The code might look like this:
#WorldsFinestMotorCar
class Jaguar extends Car {
// blah blah
}
#BoringCar
class Porche extends Car {
// blah blah
}
#BoringCar
class Ferrari extends Car {
// blah blah
}
#IncredibleCar
class Kia extends Car {
// blah blah
}
You could implement an AnnotationFilter class that removes cars from the list that do not have a certain annotation.
It might look something like this:
List<Car> carList = getListOfRandomCars();
AnnotationFilter<Car> annoFilter = new AnnotationFilter<Car>(BoringCar.class);
List<Car> boringCars = annoFilter.filter(carList);
Is that what you want to do?
If so, it can definitely be done.
The implementation for AnnotationFilter might look something like this:
public class AnnotationFilter<T> {
private Class filterAnno;
public AnnotationFilter(Class a) {
filterAnno = a;
}
public List<T> filter(List<T> inputList) {
if (inputList == null || inputList.isEmpty()) {
return inputList;
}
List<T> filteredList = new ArrayList<T>();
for (T someT : inputList) {
if (someT.getClass().isAnnotationPresent(filterAnno)) {
filteredList.add(someT);
}
}
return filteredList;
}
}
If that's not what you're after, a specific example would be helpful.
Java haven't got anything built in as such, which is why Reflections came about. Nothing built in that's as particular as what you're saying..
User-defined Annotations: we shall see how to annotate objects that we may come across in day-to-day life. Imagine that we want to persistent object information to a file. An Annotation called Persistable can be used for this purpose. An important thing is that we want to mention the file in which the information will get stored. We can have a property called fileName within the declaration of Annotation itself. The definition of the Persistable Annotation is given below,
Persistable.java
#Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE})
public #interface Persistable
{
String fileName();
}
Annotations are just a way of tagging elements of a class; how these annotations are interpreted is up to the code that defines these annotations.
Is there some built-in way of handling annotations?
Annotations are used in so many different ways that it would be difficult to come up with a few "built-in ways" of handling them. There are source-level annotations (such as #Override and #Deprecated) that do not affect the behaviour of the code at all. Then there are runtime annotations that are usually very specific to a certain library, for eg. JAXB's binding annotations only make sense within a JAXBContext and Spring's autowiring annotations only make sense within an ApplicationContext. How would Java know what to do with these annotations simply by looking at a class which uses them?
i'm just learning java, and i meet some problems.
Here we have simple factory pattern:
public class SomeFactory {
...
public static void registerProduct(String name, Class<? extends IProduct > f)
}
public SomeProduct implements IProduct {
static {
SomeFactory.register("some product", SomeProduct.class);
}
...
}
All products should register themselves at factory.
But before using this code, all Products classes should be loaded.
I can put Class.forName() somewhere, for example in main function.
But i want to avoid such sort of manual classes loading. I want just add new IProduct
implementations, without updating other parts(such as SomeFactory or Main methods, etc.).
But i wonder, is it possible to automatically load some classes(marked with annotation, for example)?
P.S I want to notice, that no other classes will be added at run-time, all IProduct implementations are known before compiling.
UPD#1
Thank for your answering!
But is it possible to make auto-generated property-file with IProduct instances?
I mean is it possible to make some build-time script(for maven for example) that generates property-file or loader code? Are there such solutions or frameworks?
UPD#2
I finished with using Reflections library that provides run-time information, by scanning classpath at startup.
This is possible, but not easily. It would need to scan all the classes in the classpath to see if they have an annotation or implement the IProduct interface. See How do you find all subclasses of a given class in Java? for answers to such a problem.
I would do keep it simple and just have a list of classes to load, either in the factory itself, or in an external file (properties file, for example).
Have each product register itself, using a static block like this:
class MyProduct1{
static{
SomeFactory.register(MyProduct1.getClass());
}
..
..
}
An external property file can keep track of all Products.
Your main method can parse this list of Products and do a Class.forName("..").
This way you wouldnt need to code any specific product, just the property file keeps changing. Ah! yes adding security registration would also be a plus point.
Note: I'm just proposing an idea, I'vent tried it myself :)
I have an annotation #MyAnnotation and I can annotate any type (class) with it. Then I have a class called AnnotatedClassRegister and I would like it to register all classes annotated with #MyAnnotation so I can access them later. And I'd like to register these classes automatically upon creation of the AnnotatedClassRegister if possible, and most importantly before the annotated classes are instantiated.
I have AspectJ and Guice at my disposal. The only solution I came up with so far is to use Guice to inject a singleton instance of the AnnotatedClassRegister to an aspect, which searches for all classes annotated with #MyAnnotation and it adds the code needed to register such class in its constructor. The downside of this solution is that I need to instantiate every annotated class in order for the code added by AOP to be actually run, therefore I cannot utilize lazy instantiation of these classes.
Simplified pseudo-code example of my solution:
// This is the class where annotated types are registered
public class AnnotatedClassRegister {
public void registerClass(Class<?> clz) {
...
}
}
// This is the aspect which adds registration code to constructors of annotated
// classes
public aspect AutomaticRegistrationAspect {
#Inject
AnnotatedClassRegister register;
pointcutWhichPicksConstructorsOfAnnotatedClasses(Object annotatedType) :
execution(/* Pointcut definition */) && args(this)
after(Object annotatedType) :
pointcutWhichPicksConstructorsOfAnnotatedClasses(annotatedType) {
// registering the class of object whose constructor was picked
// by the pointcut
register.registerClass(annotatedType.getClass())
}
}
What approach should I use to address this problem? Is there any simple way to get all such annotated classes in classpath via reflection so I wouldn't need to use AOP at all? Or any other solution?
Any ideas are much appreciated, thanks!
It's possible:
Get all paths in a classpath. Parse System.getProperties().getProperty("java.class.path", null) to get all paths.
Use ClassLoader.getResources(path) to get all resources and check for classes: http://snippets.dzone.com/posts/show/4831
It isn't simple that much is sure, but I'd do it in a Pure Java way:
Get your application's Jar location from the classpath
Create a JarFile object with this location, iterate over the entries
for every entry that ends with .class do a Class.forName() to get the Class object
read the annotation by reflection. If it's present, store the class in a List or Set
Aspects won't help you there, because aspects only work on code that's actually executed.
But annotation processing may be an Option, create a Processor that records all annotated classes and creates a class that provides a List of these classes
Well, if your AnnotatedClassRegister.registerClass() doesn't have to be called immediately at AnnotatedClassRegister creation time, but it could wait until a class is first instantiated, then I would consider using a Guice TypeListener, registered with a Matcher that checks if a class is annotated with #MyAnnotation.
That way, you don't need to search for all those classes, they will be registered just before being used. Note that this will work only for classes that get instantiated by Guice.
I would use the staticinitialization() pointcut in AspectJ and amend classes to your register as they are loaded, like so:
after() : staticinitialization(#MyAnnotation *) {
register.registerClass(thisJoinPointStaticPart.getSignature().getDeclaringType());
}
Piece of cake, very simple and elegant.
You can use the ClassGraph package like so:
Java:
try (ScanResult scanResult = new ClassGraph().enableAnnotationInfo().scan()) {
for (ClassInfo classInfo = scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName()) {
System.out.println(String.format("classInfo = %s", classInfo.getName()));
}
}
Scala:
Using(new ClassGraph().enableAnnotationInfo.scan) { scanResult =>
for (classInfo <- scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName).asScala) {
println(s"classInfo = ${classInfo.getName}")
}
}