注解apt工具示例程序
程序员文章站
2022-04-06 09:45:41
...
今天按照《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。
上面是我的一个方法,应该有更好的方法,希望大家可以分享。