我正在研究一个注释,它旨在强制一个类是不可变的。这里是处理器的代码:
@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();
// TODO
}
}
}
}
}
}
当然,注释本身是微不足道的:
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface IsImmutable {
}
我用Ant脚本编译它:
<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>
问题是,必须缺少某些东西,因为当我尝试使用由生成的jar文件提供的结果注释时,如下所示,没有任何反应:
@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);
}
}
显然,这个类不是最终的,并且该类应该在Eclipse中发出错误信号。但事实并非如此。
有什么想法吗?
编辑:我使用build.xml构建的jar文件似乎是正确的:它包含类文件,还包含META-INF/services/javax.annotation.processing.Processor
文件,其中包含archipel.immutability.IsImmutableProcessor
。我在我的测试项目中导入了这个jar文件,当我在我的Immut类中使用注释时(这只是一个粗略的测试),没有任何反应。
答案 0 :(得分:10)
默认情况下,在eclipse中禁用注释处理。为了启用它,您需要打开项目属性然后 1. Java编译器 - &gt;注释处理:启用注释处理 2. Java编译器 - &gt;注释处理 - &gt;工厂路径:添加带工厂的jar
如果您需要更多信息,请查看:getting started with AP in eclipse
<强>编辑:强>
看看这个tutorial。它详细解释了如何设置eclipse以使用自定义注释处理器。
重要提示:打印错误时请使用以下方法:javax.annotation.processing.Messager.printMessage(Kind, CharSequence, Element)
而不是:
javax.annotation.processing.Messager.printMessage(Kind, CharSequence).
消息在Problems视图和大多数与源相关的视图中可见,而来自第二个消息的消息仅在ErrorLog视图中可见。
答案 1 :(得分:0)
可能值得使用 cglib 来使对象不可变。因为想象一下你的班级和收藏领域中有一个集合是最终的。你也喜欢这个系列。这是否意味着集合不能在课外修改?不完全是。仅当此集合包含 Collections.unmodifiedCollection 方法时。 或者,如果您使用的是番石榴不可变集合http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained
重点是 - 不要试图解决这个问题,只检查字段是否为最终字段 - 它不会处理所有情况。使用 cglib 代理,例如 spring和hibernate