How can I refer to implementations of a method in annotation processing? - java

I am playing around with Java (javax) annotation processing.
Suppose I have an annotation for methods:
#Target(ElementType.METHOD)
public #interface MethodAnnotation { }
Now I want to process all the methods which are overridden from a type with the annotated method:
interface MyInterface() {
#MethodAnnotation
void f()
}
class MyClass implements MyInterface {
override void f() { } // <- I want to process this method
}
#Inherited meta-annotation seems not to be suitable here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class.
Also, is it possible to process an inherited class method which is not overridden in a subclass? Like this:
class MyClass {
#MethodAnnotation
void f() { }
}
class MySubClass extends MyClass { } // <- I want to process its f()
// or at least to find out that it doesn't
// override the method
How can I access the overriden methods of a certain method within AbstractProcessor?
I guess, to achieve this I need to find subclasses of the eclosing class, but I haven't found a way to do this either.
UPD: I suppose it's possible using RoundEnvironment.getRootElements() but still found no proper way of doing this.

The short answer is that out-of-the-box annotation processing isn't going to make this easy for you, but it can be done.
Rather than using the normal dispatch mechanism for processing, you're actually going to have to process every method and do the filtering yourself.
Step 1:
Define your processor so that it supports all annotations by using "*" as its supported annotation type. This will mean that your processor will get invoked every round.
Step 2:
Use getRootElements to get the entire set of elements every round.
Step 3:
Create an ElementScanner8 to traverse any element that you find to look for ExecutableElements. If you're willing to trust that overridden methods are annotated with #Override, you can do a quick filter on those. Otherwise, just look at all of them.
Step 4:
Now you need to see if the method overrides a method with the annotation you're looking for. There's no easy way to get methods that a given method has overridden, so you need to get the enclosing element of the method, look at its superclass and implemented interfaces (recursively), get their enclosed elements, filter out the methods, and test to see if it has been overridden by the method in question. If it has, you can check the annotations to see if it has one you care about.
Step 5:
At this point, you should have the overriding method, the overridden method and the annotation mirror that you were looking for, so you should be able to implement whatever logic you wanted.

according to the javadoc of javax.annotation.processing.Processor in Jsr269-1.8
An annotation is present if it meets the definition of being present
given in AnnotatedConstruct. In brief, an annotation is considered
present for the purposes of discovery if it is directly present or
present via inheritance. An annotation is not considered present by
virtue of being wrapped by a container annotation...
The JavaDoc of AnnotatedConstruct#getAnnotationsByType says that it returns indirectly present annotations, so I think you should scan for methods and check if they indirectly have the annotation using this call. Something in the spirit of this.
Disclaimer... haven't tried it ;)

Method annotations are not inherited. Type annotations can be inherited through the use of "#Inherited" annotation.
What you could do is define a functional interface with an inherited type annotation, however I don't know if this is elegant enough for you.

If those annotations are available at runtime, and you want to reach them at runtime, you can use the Reflections library.
For example:
Collection<URL> urls = ClasspathHelper.forPackage("nl.shopname.location.domain");
Reflections reflections = new Reflections(
new ConfigurationBuilder().setUrls(urls).setScanners(new FieldAnnotationsScanner()));
Set<Field> fieldsWithAnnotation = reflections.getFieldsAnnotatedWith(MyAnnotation.class);

Related

in java what does the # symbol mean?

I know what it means in a comment for documentation purposes, but outside of that what does it mean? (I would normally just google this but every non letter symbol shows up in results)
The # symbol denotes a Java Annotation. What a Java annotation does, is that it adds a special attribute to the variable, method, class, interface, or other language elements. (This can be configured when you declare the annotation) When you add an annotation to something, other parts of the program can check whether something has an annotation or not. It then can use this information to do whatever stuff they need.
Let me give you some examples:
The #Override annotation
public class SuperClass {
public void someInterestingMethod() {
System.out.println("Superclass!");
}
}
public class DerivedClass extends SuperClass {
public void someInterestngMethod() {
System.out.println("Derived class!");
}
}
And when you do this:
SuperClass sc = new DerivedClass();
sc.someInterestingMethod();
The someInterestingMethod() call should be dynamically dispatched, and print "Derived class!", right? Well the derived class' method was actually misspelled, so DerivedClass got its own separate method called someInterestngMethod(), totally unrelated to the superclass' someInterestingMethod(). As such, someInterestingMethod() is no longer overridden, and the superclass' implementation is invoked.
The #Override keyword is intended to help with this. It signals your intent to the compiler, that you would like the annotated method to be an overload of one of the ancestor class' methods. If it's not (such as in this typo case, or if the SuperClass API changed and renamed the method), the will fail your compilation, to alert your attention to the broken override.
The #SuppressWarnings Annotation
Here is a method:
public void someMethod() {
int i;
}
There will be a compiler warning saying that i is never used. So you can add the #SuppressWarnings to the method to suppress the warning:
#SuppressWarnings("unused")
public void someMethod() {
int i;
}
Note that there is a parameter to the #SuppressWarnings annotation. Some annotations have parameters and you can look for the them in the javadoc. But for those that don't have parameters you don't need to add () like a method.
You can also declare your own annotations and use reflection to check for them. The above 2 annotations will be checked by the compiler.
The # sign is used to specify Java Annotation.
https://en.wikipedia.org/wiki/Java_annotation
There are built-in Java Annotation and user defined Custom Annotation.
Annotations are used in various ways, such as suppress warning, associate method to URI (Servlet), associate variables to resource (JNDI) etc
The # symbol is used for annotations. In my experience, the most common annotation is #Override, which indicates that a method is declared in a superclass. Other common annotations are #Deprecated, indicating that a method should no longer be used but still exists for backwards compatibility, and #SupressWarnings, to prevent warnings from showing up in the compiler.
Note that it's actually possible to get annotations which are not included in the core Java libraries and to declare your own annotations.
The # symbol denotes Annotations. They provide information about a class, its field or method (above which they appear). They cannot perform operations. The compilers or special annotation processors use this information to make writing code less verbose.
In Java Persistence API you use them to map a Java class with database tables.
For example
#Table()
Used to map the particular Java class to the date base table.
#Entity
Represents that the class is an entity class.
Similarly you can use many annotations to map individual columns, generate ids, generate version, relationships etc.
As some other suggests, it is Java's annotation. It helps the compiler to validate your code and to notify the programmer as well.
Very simple code example:
public class SomeClass {
#Override
public String toString() {
return "SomeClass";
}
#Deprecated
public void doSomeOperation() {
// some operation...
}
}
The annotation from SomeClass#toString which is #Override helps the compiler to determine that it is an overridden function from the implicit inheritance to the class Object.
While the annotation from SomeClass#doSomeOperation will warn the programmer that the function itself is deprecated already and should be avoided to use.
The annotations are for the reader or compiler, not executable code.

How to cause a compile error/warning, when a protected (or abstract) method in the parent class is removed and sub-classes have implemented it

Let's say you you have a class called Vehicle that outlines a protected (could also be abstract) method called speed. And, the sub class Car overrides that method to define its own implementation.
Now, assume that the need to have a speed method in the Vehicle class is no longer required (let's say all vehicles will be stationary for the whatever reason).
If I remove the method speed from Vehicle, I would like to throw a compile error so that so that the developer who has removed the method knows that sub class(es) are potentially relying on it to perform certain actions.
Technically speaking a compile error is not needed, but some sort of notification that acts as a hurdle when such re factoring is happening. Is there a programming pattern that can be employed to handle such a situation?
UPDATE: I am using Java 1.4 (Sorry!)
The #Override annotation is expressly for this purpose.
If you're not using Java 1.5+, then no, although you could use AOP to instrument those methods to throw an exception, or just use reflection and classpath scanning to go over all subclasses and check for the presence of said method.
If it's abstract, then there is no implementation that can be removed from the parent class, and your risk comes down to new subclasses not implementing it. If it's protected and defined in the parent, there are two cases that should already throw compiler errors if the parent implementation is removed.
1) A subclass calls that method without defining its own implementation. Method does not exist.
2) A subclass defines the method, but includes a call to super. Again, the method does not exist.
You can write super.speed() in nested classes and leave this method empty in parent. If you delete now this method in parent, you'll have an Exception. But there is a disadvantage - you must call it from all overrided methods. Try it, perhaps this will help you
Use #Override annotation for methods in subclases.
Once you remove the method from a base-class, tools like Eclipse and javac will issue a warining for those no-longer-overriding methods.
Edit: While you cannot use #Override before Java 1.5.0, there is a tool called xdoclet. Back in the days of J2EE and EJB 2.1 this was used to "simulate" annotations and do magical things with code based on javadoc-like markers. Look at it, maybe you can use it.
Edit 2: In Java 1.4.x, you can also use JavaDoc tag {#inheritDoc} for this kind of verification. Instead of annotating your method with #Override annotate it with #inheritDoc, like this:
public class MyAwesomeClass extends BaseClass
{
/** {#inheritDoc} */
protected void myAweSomeMethod()
{
//...
}
}
Now, if you change the myAweSomeMethod signature in BaseClass, or remove it, you will get warnings from JavaDoc tool, similar to this:
/home/npe/java-tests/MyAwesomeClass.java:4: warning - #inheritDoc used but myAwesomeMethod does not override or implement any method.

Marker interface or annotations?

I need to mark some classes as Invokable - just to tell I can invoke methods of the class using reflection. But I don't like the idea of having an empty interface just for this purpose. Can this be done with annotations and still preserve behaviour on the example below? (I have never created my own annotations, so I'm not familiar with them in depth)
Example
class ClassOne implements Invokable {
}
class ClassTwo implements Invokable {
}
void someMethod(Invokable inv) {
}
Because of someMethod, you can't use annotations. Perhaps later you'll find that Invokable may need useful methods anyway.
Also, be sure to check out already existing interfaces like Callable, Future etc. before you re-invent the wheel.
You can get the annotations of a class mit Class.getAnnotations() and search for your Invokable annotation. Then you can get the method you want to invoke, and invoke it.
the decision would depend on how you are going to use these classes. if you have many classes some Invokable and some not, you may be better off with annotations, just pass the objects/ classes and check for the annotation. if you know the classes you would be passing would all be Invokable, you could go with a marker interface.
i.e. assuming you only want to preserve the behaviour and not the method :-)

Pointcut matching methods which have been annotated directly or in an inherited interface?

Consider this #PointCut which gets triggered if a method is annotated with an #Secure annotation:
#Pointcut("execution(#Secure * *(..)) && #annotation(secure)")
public void accessOperation(final Access access) { }
This works perfectly well for methods like:
class Foo {
#Secure
public void secureMethod() { }
}
But is it possible to have a Pointcut which also gets triggered when the annotation only exists in a superclass/interface like this?
interface Foo {
#Secure
public void secureMethod();
}
class SubFoo implements Foo {
#Override
public void secureMethod() { // <--- execution of this method should be caught
/* .... */
}
}
EDIT:
This seems to be very closely related to: #AspectJ pointcut for subclasses of a class with an annotation
The only difference is that they use a class-level annotation, whereas I need a method-level annotation.
I don't know how AspectJ deals with annotations in such a scenario, but if he only checks the implementing class for a certain annotation, and that annotation is only found on the interface that the class implements, Java will report that infact that annoation is not present on the class method. You should annotate your annotation with #Inherited:
http://download.oracle.com/javase/6/docs/api/java/lang/annotation/Inherited.html
maybe this will do the trick (though in this case you should make sure that your Advice is not called multiple times).
I don't actually know the classes in my aspect
Considering what you are saying and the fact that #Inherited cannot be used on anything else but classes, you are implicitly hoping that AspectJ will do the job of finding out whether a method (or its overriden implementations and declarations) is annotated. This is much more than what is announced by AspectJ.
If your final objective is to secure some code, then all methods which should be secured should be properly annotated in the first place. So, the answer to your question is no, this is not possible in this context, especially if you know nothing about the classes.
However, there might be a workaround if you have access to an annotation processor. In this case, you could pick all #Secure annotation and work your way through the code with reflection to generate AspectJ code at compile time that would captures all method instances properly. Not easy, but possible.

Using Java Annotations - Generating Code

I'm using java 6 annotation processing api. I have followed the following excellent tutorial for creating an annotation processor that displays a message at build-time:
http://kerebus.com/2011/02/using-java-6-processors-in-eclipse/
However, in my case, I have a simple class as such:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface Criteria {
String id();
double width();
double height();
}
As you can see, the aforementioned annotation is made available to the JVM at runtime using the meta-annotation 'Retention'. I use this 'Criteria' annotation in the source code of another class to annotate a method, like so:
#Criteria(id = "fooBar",
width = 22,
height = 10
)
public void fooStream() {
System.out.println("foo stream method");
}
At runtime, I want to include the 'fooStream' method in another class, ONLY if variables that are passed in match the values of the elements in the #Criteria annotation, namely 'width' and 'height'. My question is, how could I take the method 'fooStream' and inject this into another class at run-time? Is this even possible? I'm not looking for any code examples, just answers to the two aforementioned questions. Also, in the link at the top, there is an example of generating a code using 'JavaFileObject' and 'Writer' instances, where the generated code is passed as a string.
I don't believe Java supports runtime type mutation, meaning to modify the members on a given class you'd have to drop back to a compile time preprocessor or to a bytecode modification scheme.
I'd be able to point you in a better direction if I understood the "why" behind this question, but in the mean time, dynamic proxy classes might get you to where you want to be (JavaWorld article).
From the documentation:
A dynamic proxy class is a class that
implements a list of interfaces
specified at runtime such that a
method invocation through one of the
interfaces on an instance of the class
will be encoded and dispatched to
another object through a uniform
interface. Thus, a dynamic proxy class
can be used to create a type-safe
proxy object for a list of interfaces
without requiring pre-generation of
the proxy class, such as with
compile-time tools. Method invocations
on an instance of a dynamic proxy
class are dispatched to a single
method in the instance's invocation
handler, and they are encoded with a
java.lang.reflect.Method object
identifying the method that was
invoked and an array of type Object
containing the arguments.
Here's a decent tutorial on using Spring to inject dynamic proxies based on custom annotations. I think this is probably closest to the behavior you're after.
If you want runtime modification of you classes, you can use your own classloader and intercept loading of classes, introspect what you want and generate new bytecode using asm library instead of original classes. It is not very tricky, but you must be sure you need exactly that.

Categories