Is it possible to force a annotation processor to RERUN after all other processors have generated their code? Basically what I'm running into right now is that Android Databinding is generating a type parameter for one of my classes causing the inherited class from its super not to propagate properly on the first pass of my processor. Any help would be much appreciated!
Thanks
Annotation:
#Inherited
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.TYPE)
public #interface ContainsViewModel{
}
Example:
#ContainsViewModel
public class MyActivity extends ViewModelActivity<MyViewModel, GeneratedClass>{
//The GeneratedClass in this case is a SubClass of ViewDataBinding for the Android databinding library
#InjectHere
public void injectMethod(MyViewModel injected){
}
}
In the above example, the GeneratedClass will cause this class to never show up in
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
roundEnv.getElementsAnnotatedWith(ViewModelView.class)// does not have MyActivity
}
This seems to be because the GeneratedClass never gets generated until the last pass of my process. I can tell by doing,
roundEnv.getRootElements()
However, when I finally see the GeneratedClass show up, the roundEnv refuses to provide any elements with my ContainsViewModel annotation. Any ideas as to go about dealing with this? Thanks.
Related
I have a class:
public abstract class BaseDaoImpl<T extends BaseModel> implements BaseDao<T> {
}
I'm also using annotations to generate SQL queries (for various reasons I'm not able to use a framework such as hibernate) such as #Table & #Column
I would like to be able to retrieve the <T extends BaseModel> .class instance without having to take T as an input on a method.
I suppose the easy alternative would be to create a method:
public void set(Class<T> clazz){}
However I'd like to avoid this if possible to keep my code as streamlined as possible.
Is this possible?
Although using reflection is a bit of a code smell, you can get the information you need:
Class<T> modelImplementationClass = (Class<T>)
((BaseModel)this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
Reflection is a Java API that allows you to access or modify the behavior of methods, classes, interfaces at runtime.
Reflection should generally be avoided as it's quite slow and breaks abstraction by revealing internal implementation details.
Unfortunately, it's not possible to do due to type erasure: you have to force your classes to provide meta-information in runtime. I would do something like this (an adapted snippet from a big real project).
public abstract class AbstractBaseDao<T extends BaseModel> implements BaseDao<T>{
public abstract Class<T> getType();
}
class ConcreteModel extends BaseModel {/*...*/}
class ConcreteDao extends AbstractBaseDao<ConcreteModel> {
#Override
public Class<ConcreteModel> getType() {
return ConcreteModel.class;
}
}
An alternative way is to define a custom annotation like this:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Type {
Class value();
}
interface BaseDao<T extends BaseModel> { }
#Type(ConcreteModel.class)
public class ConcreteDao implements BaseDao<ConcreteModel> { }
...and use it in some processor for your DAOs, but this will require some additional infrastructure code to register all annotated classes. And - again - you cannot limit type bounds within annotations.
Custom Annotation processor is not being invoked by tomcat. Following is the Annotation processor code that I am using :
#SuppressWarnings("restriction")
#SupportedAnnotationTypes("io.strati.rs.cxf2.bindings.MyAnnotation")
#SupportedSourceVersion( SourceVersion.RELEASE_8 )
public class SimpleAnnotationProcessor extends AbstractProcessor {
public static List<String> str = new ArrayList<>();
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("Into annotation processor ... 2");
for ( Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
System.out.println("Method name is:"+element.getSimpleName());
str.add(element.getSimpleName().toString());
}
return false;
}
}
This stores the method name of all the methods that have the custom annotation. This is what the annotation class looks like :
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(value = RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
I am trying to access the list in a tomcat application as follows :
#GET
#Path("/dummy")
#MyAnnotation
#Produces({APPLICATION_JSON, APPLICATION_XML, TEXT_XML})
public void print(){
System.out.println("List is:"+SimpleAnnotationProcessor.str);
}
The list is getting printed as empty even though the method has the annotation.I have specified the annotation in the maven compiler plugin as well as specified it in META-INF/services/javax.annotation.processing.Processor. Can someone tell me what are the possible reasons due to which the annotation processor is not getting invoked ?
I doubt Tomcat has anything to do with it. Annotation processing takes place at compile time and is often used to generate or modify code. An annotation processor can be seen as a compiler plugin.
https://www.javacodegeeks.com/2015/09/java-annotation-processors.html
Following the retention policy, the annotation is going to be retained by Java compiler in the class file during the compilation phase however it will not be (and should not be) available at runtime.
It's likely the annotation processor is in fact adding the print() method name to the list (check the build output), but again this only happens when compiling the code.
The deployed web service at runtime is never going to see the list filled by the processor at compile time, those are completely different environments.
I'm trying to create an annotation which can accept multiple classes as input. Typical usage would be
#Prerequisites{FirstPrerequisite.class, SecondPrerequisite.class}
For this I can create an annotation as shown below
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Inherited
public #interface Prerequisites {
public Class<?>[] value();
}
I want to restrict the types that are allowed in the prerequisites annotation. If I give something like public Class<? extends Dependency>[] value(); It is working however, the problem is My FirstPrerequisite and SecondsPrerequisite may bot be extended from same type. I tried the following but none seemed to work, they are giving compilation errors.
public Class<? extends Dependency & TestCaseStep>[] value();
public Class<? extends Dependency , TestCaseStep>[] value();
public Class<T extends Dependency & TestCaseStep>[] value();
How to bound Generics to take inputs of two different types?
One option is to create a marker interface and have your classes implement the interface. You can then provide a bound with that interface type.
Another alternative is to simply move the constraint checking at runtime instead of at compile time. Have your annotation processor validate the Class arguments that were provided.
I am using Eclipse Juno with AspectJ and compile time weaving, and I see this annoying error message when I have this scenario:
#Configurable(preConstruction = true)
public abstract class AbstractEntity {
#Resource private Service service;
public AbstractEntity () {
service.doSomething();
}
}
public class Response extends AbstractEntity {
public Response() {
super();
}
}
The marker doesn't show up in the problems tab, it just shows a red x marker on the class declaration for Response. Cleaning doesn't change anything, however, if I move the #Configurable annotation to the Response class and remove it from the AbstractEntity, the error marker goes away but I get a NPE when the super constructor tries to touch the injected service.
Its also important to mention that this error marker doesnt actually break anything, if I leave the code the way it is everything works fine, I just always see that error marker whenever I open the class (and on any class that extends AbstractEntity).
Is there any way to stop this message from showing? is CTW changing the constructor hierarchy behind the scenes which causes this message?
For the following custom Java annotation
#CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode
{
...
}
I basically want to be able to grab both the Class object for the MyApplicationCode and the clazz parameter at compile time to confirm some coding convention consistencies (another story). Basically I want to be able to access MyApplicationCode.class and Someclass.class code in the annotation processor. I'm almost there but I'm missing something. I have
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.SOURCE)
public #interface CustomAnnotation
{
public Class clazz();
}
Then I have for the processor:
public class CustomAnnotationProcessor extends AbstractProcessor
{
private ProcessingEnvironment processingEnvironment;
#Override
public synchronized void init(ProcessingEnvironment processingEnvironment)
{
this.processingEnvironment = processingEnvironment;
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)
{
Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);
for(Element e : elements)
{
Annotation annotation = e.getAnnotation(CustomAnnotation.class);
Class clazz = ((CustomAnnotation)annotation).clazz();
// How do I get the actual CustomAnnotation clazz?
// When I try to do clazz.getName() I get the following ERROR:
// Attempt to access Class object for TypeMirror SomeClass
// Also, how do I get the Class object for the class that has the annotation within it?
// In other words, how do I get MyApplicationCode.class?
}
}
}
So what I'm trying to do in the process method is to grab SomeClass.class and MyApplication.class from the original code below to do some custom validation at compile time. I can't seem for the life of me figure out how to get those two values...
#CustomAnnotation(clazz=SomeClass.class)
public class MyApplicationCode
Update: The following post has a lot more details, and it's much closer. But the problem is that you still end up with a TypeMirror object from which to pull the class object from, which it doesn't explain: http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/
Update2: You can get MyApplication.class by doing
String classname = ((TypeElement)e).getQualifiedName().toString();
I was going to point you in the direction of the blog http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/, but it looks like you already found that one.
I see you figured out how to access the MyApplication Element, so I wont cover that....
The exception you see actually contains the type of the annotation property within it. So you can reference the annotation clazz value when you catch the exception:
public class CustomAnnotationProcessor extends AbstractProcessor
{
private ProcessingEnvironment processingEnvironment;
#Override
public synchronized void init(ProcessingEnvironment processingEnvironment)
{
this.processingEnvironment = processingEnvironment;
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment)
{
Set<? extends Element> elements = environment.getElementsAnnotatedWith(ActionCommand.class);
for(Element e : elements)
{
CustomAnnotation annotation = e.getAnnotation(CustomAnnotation.class);
TypeMirror clazzType = null;
try {
annotation.clazz();
} catch (MirroredTypeException mte) {
clazzType = mte.getTypeMirror();
}
System.out.println(clazzType); // should print out SomeClass
}
}
}
Yes, this is a total hack of a solution, and I'm not sure why the API developers decided to go this direction with the annotation processor feature. However, I have seen a number of people implement this (including myself), and the article mentioned describes this technique as well. This seems to be an acceptable solution at the moment.
In terms of "grabbing" the class values for MyApplicationCode and SomeClass, you will not be able to do so if they are classes being compiled. You can, however, use the Element and TypeMirror representations to perform some high level validation on your classes (Method, Field, Class names, annotations present, etc)
After reading this related SO question, I found this excellent page about the Java Annotation Processing Tool (APT). It's from 2005 so may not be the best way to do this these days.
APT [...] is an annotation processing tool for Java. More specificially, APT allows you to plug code in to handle annotations in a source file as the code compilation is occurring - and in that process, you can emit notes, warnings, and errors.
More information about APT in Java 6 from Oracle's docs.
Interesting blog post from someone at Oracle about APT.
Another example usage of APT -- this time from 2009.
This is only for Oracle's JDK.
It is compile time. I would think the compiler is not even finished up compiling the source code. You retrieve such information from AnnotatedElement instance which will give you relevant information of the type you have annotated, but not its runtime properties, thats not yet available since the relevant class files are not yet loaded by the virtual machine. And the compiler is not even guaranteed to be running under a virtual machine for java, so it is not mandated to be able to load class files. Its requirement is only to be able to produce bytecodes that any particular virtual machine can read.
So go check on the mirror Api, and for any relevant information on the class/method/field you have annotated, check on AnnotatedElement representing that instance.
And as aside note: this is information is just what i reasoned up, so it might not be the actual truth.