今天按照《Thinking in Java》中使用apt处理注解一节,将书中代码写了一遍,但运行过程中出现了一个问题让我很纳闷,下面先把代码呈上,问题稍后再说。
程序功能很简单,就是从被注解的类中提取出public方法,然后使用注解处理器生成一个包含这些public方法的接口文件。
具体介绍可以参考原书。
ExtractInterface.java——注解定义
/**
*
*/
package net.lazydoggy.annotations.aptdemo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author hanzhaozhan
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ExtractInterface {
String value();
}
Multiplier.java——使用了注解的目标类
/**
*
*/
package net.lazydoggy.annotations.aptdemo;
/**
* @author hanzhaozhan
*
*/
@ExtractInterface("Imultiplier")
public class Multiplier {
public int multiply(int x, int y) {
int total = 0;
for (int i = 0; i < x; i++) {
total = add(total, y);
}
return total;
}
private static int add(int x, int y) {
return x + y;
}
public static void main(String[] args) {
Multiplier m = new Multiplier();
System.out.println("11 * 16 = " + m.multiply(11, 16));
}
}
InterfaceExtractorProcessor.java——注解处理器类
package net.lazydoggy.annotations.aptdemo;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
public class InterfaceExtractorProcessor implements AnnotationProcessor {
private final AnnotationProcessorEnvironment env;
private ArrayList<MethodDeclaration> interfaceMethods = new ArrayList<MethodDeclaration>();
public InterfaceExtractorProcessor(AnnotationProcessorEnvironment env) {
this.env = env;
}
@Override
public void process() {
for (TypeDeclaration typeDel : env.getSpecifiedTypeDeclarations()) {
ExtractInterface annot = typeDel
.getAnnotation(ExtractInterface.class);
if (annot == null) {
break;
}
for (MethodDeclaration m : typeDel.getMethods()) {
if (m.getModifiers().toString().contains("public")
&& !(m.getModifiers().toString().contains("static"))) {
interfaceMethods.add(m);
}
}
if (interfaceMethods.size() > 0) {
try {
PrintWriter writer = env.getFiler().createSourceFile(
annot.value());
writer.println("package "
+ typeDel.getPackage().getQualifiedName() + ";");
writer.println("public interface " + annot.value() + " {");
for (MethodDeclaration m : interfaceMethods) {
writer.print("\tpublic ");
writer.print(m.getReturnType() + " ");
writer.print(m.getSimpleName() + "(");
int i = 0;
for (ParameterDeclaration param : m.getParameters()) {
writer.print(param.getType() + " "
+ param.getSimpleName());
if (++i < m.getParameters().size()) {
writer.print(",");
}
}
writer.println(");");
}
writer.println("}");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
InterfaceExtractorProcessorFactory.java——处理器工厂类
/**
*
*/
package net.lazydoggy.annotations.aptdemo;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
/**
* @author hanzhaozhan
*
*/
public class InterfaceExtractorProcessorFactory implements
AnnotationProcessorFactory {
/*
* (non-Javadoc)
*
* @see
* com.sun.mirror.apt.AnnotationProcessorFactory#getProcessorFor(java.util
* .Set, com.sun.mirror.apt.AnnotationProcessorEnvironment)
*/
@Override
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> atds,
AnnotationProcessorEnvironment env) {
return new InterfaceExtractorProcessor(env);
}
/*
* (non-Javadoc)
*
* @see
* com.sun.mirror.apt.AnnotationProcessorFactory#supportedAnnotationTypes()
*/
@Override
public Collection<String> supportedAnnotationTypes() {
return Collections
.singleton("net.lazydoggy.annotations.aptdemo.ExtractInterface");
}
/*
* (non-Javadoc)
*
* @see com.sun.mirror.apt.AnnotationProcessorFactory#supportedOptions()
*/
@Override
public Collection<String> supportedOptions() {
return Collections.emptySet();
}
}
使用下面命令:
apt -s . -nocompile -factory net.lazydoggy.annotations.aptdemo.InterfaceExtractorProcessorFactory .\net\lazydoggy\annotations\aptdemo\Multiplier.java
就会在当前执行目录下生成一个Imultiplier .java文件,里面定义了我们在处理器中写入的接口。
上面的程序运行时没有问题的,因为其中的一行代码被我改动过,如下:
for (MethodDeclaration m : typeDel.getMethods()) {
if (m.getModifiers().toString().contains("public")
&& !(m.getModifiers().toString().contains("static"))) {
interfaceMethods.add(m);
}
}
书中的代码是这样的:
for (MethodDeclaration m : typeDel.getMethods()) {
if (m.getModifiers().contains(Modifier.PUBLIC)
&& !(m.getModifiers().contains(Modifier.STATIC))) {
interfaceMethods.add(m);
}
}
如果使用书中的代码是无法得到预期结果的,我使用JDK1.6,不知道JDK1.5是否可以。在JDK1.6中,getModifiers()返回Collection<Modifier>类型,而Modifier类中的静态常量(PUBLIC、STATIC等)是int类型,因此书中代码总会返回false。
上面是我的一个方法,应该有更好的方法,希望大家可以分享。