I am working on an annotation whose purpose is mandatory for the class to be immutable. Here is the processor code:
@SupportedAnnotationTypes("archipel.immutability.IsImmutable") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class IsImmutableProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement type : annotations) { processMustBeImmutable(roundEnv, type); } return true; } private void processMustBeImmutable(RoundEnvironment env, TypeElement type) { for (Element element : env.getElementsAnnotatedWith(type)) { processClass(element); } } private void processClass(Element element) { boolean isFinal=false; for(Modifier modifier : element.getModifiers()) { if (modifier.equals(Modifier.FINAL)) { isFinal=true; break; } } if (!isFinal) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Class "+element+" is not immutable because it is not final"); } else { for (Element subElement : element.getEnclosedElements()) { if (subElement.getKind()==ElementKind.FIELD) { isFinal=false; for(Modifier modifier : subElement.getModifiers()) { if (modifier.equals(Modifier.FINAL)) { isFinal=true; break; } } if (!isFinal) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Field "+element+" is not immutable because it is not final"); } else { Element superElement = subElement.getEnclosingElement();
Of course, the annotation itself is trivial:
@Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface IsImmutable { }
And I will compile it with Ant script:
<project name="immutability" basedir="." default="main"> <property name="lib.dir" value="lib"/> <property name="src.dir" value="src"/> <property name="build.dir" value="build"/> <property name="classes.dir" value="${build.dir}/classes"/> <property name="meta.dir" value="${build.dir}/META-INF"/> <property name="jar.dir" value="${build.dir}/jar"/> <property name="processor-package" value="archipel.immutability" /> <property name="processor" value="${processor-package}.IsImmutableProcessor"/> <path id="classpath"> <fileset dir="${lib.dir}" includes="**/*.jar"/> <fileset dir="${classes.dir}"/> </path> <target name="clean"> <delete dir="${build.dir}"/> </target> <target name="compile" description="Compiles the code."> <mkdir dir="${classes.dir}"/> <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" /> </target> <target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile="${jar.dir}/${ant.project.name}.jar"> <fileset dir="${classes.dir}"/> <service type="javax.annotation.processing.Processor" provider="archipel.immutability.IsImmutableProcessor"/> </jar> </target> <target name="main" depends="clean,jar"/> </project>
The problem is that something must be missing, because when I try to use the received annotation provided by the received jar file, like the following, nothing happens:
@IsImmutable public class Immut { private int toto; public int getToto() { return toto; } public void setToto(int toto) { this.toto = toto; } public final static void main(String args[]) { Immut truc = new Immut(); truc.setToto(5); truc.setToto(6); } }
Obviously, this class is not final, and the class should signal an error in Eclipse. But this is not so.
Any idea?
Change The jar file that I created with my build.xml seems to be correct: it contains class files, as well as a META-INF/services/javax.annotation.processing.Processor
containing archipel.immutability.IsImmutableProcessor
. I import this jar file into my test project, and when I use the annotation in my Immut class (this is just a rough test), nothing happens.