I have an annotation that can be added on METHOD
and TYPE
and is used in thousands of places in our project.
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD, TYPE})
@Inherited
public @interface RequiredStore{
Store value();
}
Is it possible to make the annotation deprecated only on methods while keeping it non-deprecated on types? I want other developers to be notified by IDE that it should not be used on methods any more, until we'll refactor all existing usages and finally remove the METHOD
part.
If it's not possible, is there any Way to handle such case beside creating new annotation only for types and deprecating the old one?
You could use an annotation Processor.
For example, the annotation and its processor would be placed in its own .jar
file and added as a dependency of the sources that use the annotation.
The custom .jar
would have the following structure:
src/main/ java/com/company/annotations/ RequiredStore.java RequiredStoreProcessor.java resources/META-INF/services javax.annotation.processing.Processor
RequiredStore.java
stays as you have it above.
RequiredStoreProcessor.java
could look something like this:
package com.company.annotations;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes("com.company.annotations.RequiredStore")
public class RequiredStoreProcessor extends AbstractProcessor {
@Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element
: roundEnv.getElementsAnnotatedWith(RequiredStore.class)) {
if (element.getKind().equals(ElementKind.METHOD)) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
"Using @RequiredStore on methods has been deprecated\n"
+ "Class: " + element.getEnclosingElement() + "\n"
+ "Method: " + element.getSimpleName() + "\n");
}
}
// Other processing...
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
The javax.annotation.processing.Processor
file allows javac
to pickup the Processor via SPI and simply contains
com.company.annotations.RequiredStoreProcessor
Finally, compile this into a .jar
and add it to the classpath where the annotations are being used. Any methods that have the @RequiredStore
will produce a compiler warning. For example, for this class,
package com.company.business;
import com.company.annotations.RequiredStore;
@RequiredStore
public interface Business {
@RequiredStore
public void someMethod();
}
The compiler warning would be this:
warning: Using @RequiredStore on methods has been deprecated Class: com.company.business.Business Method: someMethod
As for an indication in the IDE, you might have to write a custom inspection and unfortunately this depends on the IDE used.
Decent custom annotations reference: Code Generation using Annotation Processors in the Java language
If you are okay about using native aspectj, another option is to use AspectJ's code enforcement policy this way:
public aspect RequiredStoreAnnotationCheck {
declare warning: execution(@RequiredStore * *.*(..)) : "Required store annotation not appropriate for methods..";
}
If the IDE is integrated with AspectJ, this would be flagged as a compile time check.
AspectJ in action book has a good amount of detail on this too.
Here is one of my blog articles for more context: http://www.java-allandsundry.com/2012/03/code-policy-enforcement-using-aspectj.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With