I have a VariableElement field that is annotated with a generated Annotation (which is why I can't use field.getAnnotation(annotationClass)). I need to get all parameters passed to this annotation.
Note that by "a generated Annotation" I mean that literally the Annotation class itself (not the annotated one) has been generated by an Annotation Processor. The field/class that is being annotated is in the handwritten source code.
It didn't look like it'd be that hard, so far I've come up with this:
for (AnnotationMirror annotation : field.getAnnotationMirrors()) {
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValueMap = annotation.getElementValues();
messager.printMessage(Diagnostic.Kind.WARNING, annotation.toString() + ":" + annotationValueMap.toString());
}
I thought this would do it, but the output for the field is the following:
#MyAnnotation:{}
So, the processor does recognize that the field is annotated, but I'm unable to access the passed parameters. Even though the field is definetely annotated and does pass parameters with the annotation (it has to, since the annotation defines required parameters and no defaults):
#MyAnnotation(max = 387, min = 66876, ...)
private Integer myField;
Here's the generated annotation code:
#Retention(RetentionPolicy.SOURCE)
#Target(ElementType.FIELD)
public #interface MyAnnotation {
int max();
boolean allowAuto();
int min();
}
I've clean-compiled the project multiple times, the processor never sees the values. What am I overlooking here? The processor can obviously see the annotation itself, yet the parameters passed to it are hidden.
Recall that annotation processors run as part of the compiler, in steps called "rounds". This process runs iteratively until there is no new code to compile, and then processors get one last chance to run (not necessary for this answer, but helpful for more context). Each round only the newly created types are directly given to the processor to examine.
What seems to be happening here is that during a round you are emitting a new annotation type, which should allow the processor to observe certain features about some code submitted to be compiled. However, any types created during a given round are not yet compiled until the next round begins.
For this question, we run into a conflict here - some Java sources are compiled which use an annotation that doesn't exist yet. The processor first creates the annotation, and then tries to read the newly-created annotation out of those partly-compiled sources. Unfortunately, until the annotation has been compiled, we can't actually read the annotation. Instead, we need to wait until the subsequent round (once the annotation itself has compiled), then go back to that class which has finished being compiled and examine it.
This can be implemented yourself without too much trouble, but the easiest way is often to rely on the google/auto project (specifically the auto-common library, see https://github.com/google/auto/tree/master/common), and extend their BasicAnnotationProcessor class. One of the nice features it supports is to automatically examine types and check if there are any compilation issues - if so, they are deferred until a later round so you can handle them without any type resolution issues.
Use getAnnotation(MyAnnotation.class) available from VariableElement
in your example code you can do this to get the min and max parameters
MyAnnotation myAnnotation= field.getAnnotation(MyAnnotation.class);
int max = myAnnotation.max();
int min = myAnnotation.min();
this will work unless the annotation members returns class/class[] value, in which you will get an exception if you try to get the value using this method.
more about how to get class literal values can be found on this answer
How to read a Class[] values from a nested annotation in an annotation processor
Or using annotation mirrors
for (AnnotationMirror annotation : field.getAnnotationMirrors()) {
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValueMap = annotation.getElementValues();
annotationValueMap.forEach((element, annotationValue) -> {
messager.printMessage(Diagnostic.Kind.WARNING, element.getSimpleName().toString() + ":" + annotationValue.getValue());
});
}
In case you have more than one annotation on the field then you can iterate over the annotation mirrors and use the check types.isSameType(annotationMirror.getAnnotationType(), elements.getTypeElement(MyAnnotation.class.getName()).asType()) to find the annotation you are interested in
Yes, you will not be able to instantiate a Class object for a type which is not available in your annotation processor's classloader, and may not even have been compiled into a class file yet at all. A similar problem exists for retrieving enum constants.
There are a few wrinkles to dealing with this sort of thing:
Any annotation value that is declared as an array might come to you at compile time either as a single value, or a list of values - so any code needs a path to handle both the list and non-list case - like this
What you get may be a generic type, and if you are generating Java code or similar that wants to insert a reference to Foo.class you need to get the erasure of that type, so you don't generate Foo<Bar>.class into your generated sources.
One of the places your annotation processor is going to get run is in an IDE, on broken code still being typed, so it is important to fail gracefully in the case that code elements that, you would think, can't possibly be missing or broken or unlikely values, are. In an IDE, your annotation processor may also be kept alive for a long time and reused, so it's important not to pile up objects modeling stuff that has already been generated and emitted.
FWIW, I wrote a library to solve this and related problems, which can be found on Maven central at the coordinates com.mastfrog:annotations-tools:2.8.3.4 (check for newer versions). The usage pattern is simple:
Instantiate an instance of AnnotationUtils in an override of the init() method of your annotation processor and store it in a field
Use it to, for example, resolve a Class<?>[] into a list of string class names that you can work with inside javac, and similar
It makes it pretty straightforward to write annotation processors that do not directly depending on the classes they processes at all - which means the annotation processors (and their dependency graphs!) be completely independent of what they process, and can depend on whatever libraries they like without forcing those dependencies into the dependency graph of any project that uses them - the most common pattern is someone writes some annotations and then puts the annotation processor in the same project, or even package, and so anything the annotation processor uses becomes a dependency of every consumer of the annotations, even though those dependencies will probably never be used at runtime at all. That, it seems to me, is an antipattern worth avoiding.
I'm trying to somehow 'debug' my application that use the spring boot cache annotations and for that I would like to know how to find the class that actually implements the interface Cacheable, CacheConfig, etc.
My idea is to confirm that the cache is being populated, emptied etc.
Thanks a lot for your help,
#Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name of the cache associated with the annotated method:
#Cacheable("books")
public Book findBook(ISBN isbn) {...}
In the snippet above, the method findBook is associated with the cache named books. Each time the method is called, the cache is checked to see whether the invocation has been already executed and does not have to be repeated. While in most cases, only one cache is declared, the annotation allows multiple names to be specified so that more than one cache are being used. In this case, each of the caches will be checked before executing the method - if at least one cache is hit, then the associated value will be returned.
For more information read the following;
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache
Spring used ConcurrentHashMap as the default cache implementation.
public class ConcurrentMapCache extends AbstractValueAdaptingCache
If, on the other hand, you need different cache, then Spring also comes with a built in ehCache wrapper. The good news is that swapping between Spring's caching implementations is easy. In theory it’s all a matter of configuration.
I added the following method to one of my application entity.
public boolean isSame(TaskUser taskUser){
//some work
}
However I came across few threads like this one regarding hibernate errors for such kind of methods used without #Transient. But my application is running fine and also there is no column created in my DB table for the entity, so as a learner I want to ask what actually happens that save my app from hibernate error. Is that argument passed the reason?
This method does not define a property, so Hibernate is not interested in mapping a column for it.
The reason is that it is not a "getter". It does have the proper name ("isXXX" for a boolean), but it takes a parameter. Getters must be without parameters.
If it was a "real" getter, and you did not want it to result in a persistent property, you could use #Transient to suppress the automatic mapping.
Using jersey - I know I can annotate a method with
#Path("/{a:path1|path2}")
but I was wandering if it was also possible to just use two annotations on a single method
#Path("path1")
#Path("path2")
To get almost the same effect (I know - this way I can not get a #PathParam ).
Only in Java 8 it is allowed to have more than one same annotation. And even more than that annotation should be marked specially (#Repeatable, see more info here). Annotation #Path does not have such meta-annotation.
So, conclusion it is not possible.
On Camel 2.10.1, the following worked:
<camel:bean ref="profilingBean" method="addProfilingContext('TEST')"/>
The method in question takes a String parameter
Migrating to 2.10.6 , this does not work anymore, it tries to call TEST as another class. I have tried wrapping with ${} , trying to use exotic combinations of "& quot;" etc...
The only solution I found was to put the value in a header using constant language then call the header using simple. Obviously, this isn't very clean...
Do you have any ideas how to do this?
Cheers
The behavior/bug still exists in Camel 2.16 and also in latest 2.18.2.
For every string constant that is passed to a bean via Spring DSL a java.lang.ClassNotFoundException is thrown.
It gets more visible by setting logger for org.apache.camel.util.ObjectHelper to TRACE.
This camel behavior also has serious negative performance impact because ClassLoader method (java.lang.ClassLoader.loadClass) is synchronized for a given parameter name.
I wrote a little demo to show this: https://github.com/groundhog2k/camel-dsl-bean-bug
Your solution with the header is fine. The bug you talk about should be fixed in 2.10.7, or 2.11.1 etc.