I'd like to implement an annotation for methods which will let me know where those annotated methods called, just like official #deprecated annotation.
How can I get the list of all calling methods for a given annotated method?
I think this question may help you:
To find this annotated method (from Arthur Ronald's answer):
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());
Or (from Jonathan's answer):
Google reflections:
https://github.com/ronmamo/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.
Google reflections pulls in Google collections. Indexes everything and then is super fast.
Update: If want to calling methods for a given annotated method, you should use AOP (Aspect Oriented Programming) and add # Around or # Before, for example something like this (I don't check this code):
public class Foo {
#YourAnnotation
public int power(int x, int p) {
return Math.pow(x, p);
}
}
#Aspect
public class MethodLogger {
#Around("execution(* *(..)) && #annotation(YourAnnotation)")
public Object around(ProceedingJoinPoint point) {
Logger.info(
"call by method" + MethodSignature.class.cast(point.getSignature()).getMethod().getName()
);
Object result = point.proceed();
return result;
}
}
Related
I have a class A with a bunch of methods I have annotated the same with unique Annotations. I want to invoke the method at runtime given the specific annotation. Also, I might have to pass parameters as well.
public class XYZAccessor(){
#CustomAnnotation(id="methodAIdentifier")
public String methodA(){
return "A";
}
#CustomAnnotation(id="methodBIdentifier")
public String methodB(){
return "B";
}
#CustomAnnotation(id="methodCIdentifier")
public int methodC(int param){
return (5+param);
}
}
Given the string "methodAIdentifier", I would like to invoke XYZAccessor.methodA();
I have seen these approaches for the same.
1) Java Reflection: XYZAccessor.getClass.getMethods.getAnnotations()
Iterate through that and find the specific method and invoke it.
2) Google Reflections: These have javaassist and guava as a dependancy.
Use their framework Class.getMethodAnnotatedWith("methodAIdentifier")
3) AspectJ: I am not clear on how to use Aspect for this use case. Something like a pointcut and an #Around. Something like
Pointcut matching methods with annotated parameters
Which of these approaches is the most efficient and the best approach to this problem?
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();
}
}
With Google Guice or Gin I can specify parameter with are not controlled by the dependency injection framework:
class SomeEditor {
#Inject
public SomeEditor(SomeClassA a, #Assisted("stage") SomeClassB b) {
}
}
The assisted parameter stage is specified at the time an instance of SomeEditor is created.
The instance of SomeClassA is taken from the object graph and the instance of SomeClassB is taken from the caller at runtime.
Is there a similar way of doing this in Dagger?
UPDATE: As of Dagger 2.31 from January 2021, Dagger now natively supports assisted injection, which is recommended over the Square and Auto options. (Those other options still work, but may require extra setup compared to the native option.)
class SomeEditor {
#AssistedInject public SomeEditor(
SomeClassA a, #Assisted SomeClassB b) {
// ...
}
}
#AssistedFactory interface SomeEditorFactory {
SomeEditor create(SomeClassB b);
}
(original answer)
Because factories are a separate type of boilerplate to optimize away (see mailing list discussion here), Dagger leaves it to a sister project, AutoFactory. This provides the "assisted injection" functionality Guice offers via FactoryModuleBuilder, but with some extra benefits:
You can keep using AutoFactory with Guice or Dagger or any other JSR-330 dependency injection framework, so you can keep using AutoFactory even if you switch between them.
Because AutoFactory generates code, you don't need to write an interface to represent the constructor: AutoFactory will write a brand new type for you to compile against. (You can also specify an interface to implement, if you'd prefer, or if you're migrating from Guice.)
Because all the type inspection happens at compile-time, it produces plain old Java, which doesn't have any slowness due to reflection and which works well with debuggers and optimizers. This makes the Auto library particularly useful for Android development.
Example, pulled from AutoFactory's README, which will produce a SomeClassFactory with providedDepA in an #Inject-annotated constructor and depB in a create method:
#AutoFactory
final class SomeClass {
private final String providedDepA;
private final String depB;
SomeClass(#Provided #AQualifier String providedDepA, String depB) {
this.providedDepA = providedDepA;
this.depB = depB;
}
// …
}
Just like #xsveda, I also wrote an answer about this in this other question, which I'll also reproduce here.
Today, for assisted injection with Dagger you probably want to use AssistedInject. I wrote about it in this blogpost, but I'll add a full example here to make things easier.
First thing you need are the dependencies:
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
Then here's how it can look like:
class ImageDownloader #AssistedInject constructor(
private val httpClient: HttpClient,
private val executorService: ExecutorService,
#Assisted private val imageUrl: URL,
#Assisted private val callback: ImageCallback
) {
#AssistedInject.Factory
interface Factory {
fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
}
}
First thing is that instead of annotating the constructor with #Inject, we annotate it with #AssistedInject. Then we annotate the parameters that will have to go through the factory, which is the opposite of what AutoFactory expects. Finally, we need an inner factory interface annotated with #AssistedInject.Factory that has a single method that receives the assisted parameters and returns the instance we're interested in.
Unfortunately, we still have an extra step here:
#AssistedModule
#Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
We don't necessarily need a dedicated module for it, even though that's a valid option. But we can also have those annotations in another module that is already installed in the component. The nice thing here is that we only need to do it once, and after that any factory will automatically become part of the graph.
With that, you can basically inject the factory and ask for your object as you'd normally do.
Yes, please check this Square project: square/AssistedInject
Currently it is not in 1.0 yet for purpose. They wait until Dagger will introduce a public API for registering those generated Module classes automatically - see this issue. With that you won't have to reference them in your Dagger code as in this example from README:
#AssistedModule
#Module(includes = AssistedInject_PresenterModule.class)
abstract class PresenterModule {}
I am currently experimenting with Spring and its AOP features.
What I would like to know is if it is possible to extend the expression language of pointcut definition somehow...
I am quite familiar with the standard behaviour and usage of pointcut designators Spring provides but for my needs I would like to implement my own one.
Say we have a method in our aspect:
#Aspect
public class AspectClass {
#Before("execution(* *.get*(..)) && #annotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation) {
System.out.println("Doing stuff!");
}
}
Now what I would like is something like this:
...
#Before("execution(* *.get*(..)) && #myAnnotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation){
...
Where the myAnnotation(..) token is my custom extension of the expression language.
When I delved into Spring implementation I found where the parser resides and the fact it is hard-coded into AspectJExpressionPointcut implementation. Hence providing a custom implementation of said parser and sticking it someplace in some bean initialization routine seems like a no-no.
Exemplary usage of this extension would be for example matching a method by it's annotation, disregarding proximity of this annotation in the object hierarchy. So it would match a method that is overriden and whose annotation is defined on the parent's implementation.
public abstract class Superclass {
#SomeAnnotation
public abstract String getValue();
}
public class TheClass extends Superclass {
#Override
public String getValue() { // <- this would get advised by Spring using formerly defined aspect
// return some stuff
}
}
I know that I can reflect the method in the advice and check if the annotation is present on some method of some superclass, but I would like to encapsulate this process and offer it for convenient usage.
Have you guys stumbled upon something like this & can you offer me a solution (if it is possibe) / explanation (if it is not)? :-)
Thanks in advance, Janek.
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}")
}
}