I think that a custom annotation, which will be processed by the compiler, is the solution. I frequently write custom annotations to do things at runtime, but I never tried to use them at compilation time. So, I can only give you pointers on the tools you may need :
- Write a custom annotation type. This page explains how to write an annotation.
- Write an annotation processor, that processes your custom annotation to emit a warning. The tool that runs such annotation processors is called APT. You can find an indroduction on this page. I think what you need in the APT API is AnnotationProcessorEnvironment, which will let you emit warnings.
- From Java 6, APT is integrated into javac. That is, you can add an annotation processor in the javac command line. This section of the javac manual will tell you how to call your custom annotation processor.
I don't know if this solution is really practicable. I'll try to implement it myself when I find some time.
Edit
I successfully implemented my solution. And as a bonus, I used java's service provider facility to simplify its use. Actually, my solution is a jar that contains 2 classes : the custom annotation and the annotation processor. To use it, just add this jar in the classpath of your project, and annotate whatever you want ! This is working fine right inside my IDE (NetBeans).
Code of the annotation :
package fr.barjak.hack;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})
public @interface Hack {
}
Code of the processor :
package fr.barjak.hack_processor;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
@SupportedAnnotationTypes("fr.barjak.hack.Hack")
public class Processor extends AbstractProcessor {
private ProcessingEnvironment env;
@Override
public synchronized void init(ProcessingEnvironment pe) {
this.env = pe;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
for (TypeElement te : annotations) {
final Set< ? extends Element> elts = roundEnv.getElementsAnnotatedWith(te);
for (Element elt : elts) {
env.getMessager().printMessage(Kind.WARNING,
String.format("%s : thou shalt not hack %s", roundEnv.getRootElements(), elt),
te);
}
}
}
return true;
}
}
To enable the resulting jar as a service provider, add the file META-INF/services/javax.annotation.processing.Processor
in the jar. This file is an acsii file that must contain the following text :
fr.barjak.hack_processor.Processor