今天按照《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。
上面是我的一个方法,应该有更好的方法,希望大家可以分享。