apt.exe 是 Java SE 5 中新增的一个工具,它是 Annotation Processing Tool(APT)的缩写。APT 工具可以用来处理 Java 代码中的注解,并生成新的 Java 代码。APT 工具可以自动化生成代码,减少手动编写代码的工作量,提高代码的可读性和可维护性。
以下是 apt.exe 命令语法:
apt -processor <processor_class> <source_files>
其中:
-processor <processor_class> 指定要使用的注解处理器类。
<source_files> 指定要处理的源文件。
请注意,APT 工具需要 JDK 5 或 JDK 6 来运行。在 JDK 7 及更高版本中,apt.exe 已经被 javac 工具所取代,可以通过 javac 的 -processor 选项来指定注解处理器。或者,使用 javax.annotation.processing API 和自定义注解处理器来代替 APT 工具。API 如下图:
以下是一个简单的示例,演示如何使用 javac 的 -processor 注解处理器来处理自定义注解。
(1)定义一个自定义注解 @MyAnnotation:
package com.hxstrive.apt; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义一个注解 * @author HuangXin * @since 1.0.0 2024/2/28 10:09 */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) public @interface MyAnnotation { String value(); }
(2)创建一个注解处理器 MyAnnotationProcessor:
package com.hxstrive.apt; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import java.util.Set; /** * 注解处理器 * @author HuangXin * @since 1.0.0 */ // 指定该注解处理器可以解决的类型,需要完整的包名+类命 @SupportedAnnotationTypes("com.hxstrive.apt.MyAnnotation") // 指定编译的JDK版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class MyAnnotationProcessor extends AbstractProcessor { // 这里就是处理注解的process函数 @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { System.out.println("======================="); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Processing annotations..."); for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { MyAnnotation annotation = element.getAnnotation(MyAnnotation.class); String value = annotation.value(); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Found @MyAnnotation with value: " + value); } return true; } }
(3)创建一个测试类 TestClass,并在方法上使用 @MyAnnotation 注解:
package com.hxstrive.apt; /** * 测试类 * @author HuangXin * @since 1.0.0 */ public class TestClass { @MyAnnotation("Hello, Annotation Processing!") public void testMethod() { System.out.println("This is a test method."); } }
编译方式一:
(1)使用不带有 -processor 的 javac 命令编译注解处理器,例如:
E:\demo\src\main\java>javac -encoding UTF-8 -cp .;./classes -d classes ./com/hxstrive/apt/*.java
(2)使用带有 -processor 编译代码,例如:
E:\demo\src\main\java>javac -encoding UTF-8 -cp .;./classes -processor com.hxstrive.apt.MyAnnotationProcessor ./com/hxstrive/apt/TestClass.java ======================= 注: Processing annotations... 注: Found @MyAnnotation with value: Hello, Annotation Processing! ======================= 注: Processing annotations...
编译方式二:
(1)在源码根目录下面创建 META-INF\services\javax.annotation.processing.Processor 文件,文件内容为自定义注解处理器的完全限定类名 com.hxstrive.apt.MyAnnotationProcessor。
(2)使用不带 -processor 的 javac 命令编译源码,如下:
E:\demo\src\main\java>javac -encoding UTF-8 -cp .;./classes -d classes ./com/hxstrive/apt/*.java ======================= 注: Processing annotations... 注: Found @MyAnnotation with value: Hello, Annotation Processing! ======================= 注: Processing annotations...
通过输出可知,注解处理器已经被触发了。
下面将利用注解处理器动态创建代码:
(1)定义一个自定义注解 @MyAnnotation:
package com.hxstrive.apt2; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义一个注解 * @author HuangXin * @since 1.0.0 2024/2/28 10:09 */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) public @interface MyAnnotation { String value(); }
(2)创建一个注解处理器 MyAnnotationProcessor:
package com.hxstrive.apt2; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.Writer; import java.util.Set; /** * 注解处理器 * @author HuangXin * @since 1.0.0 */ // 指定该注解处理器可以解决的类型,需要完整的包名+类命 @SupportedAnnotationTypes("com.hxstrive.apt2.MyAnnotation") // 指定编译的JDK版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class MyAnnotationProcessor extends AbstractProcessor { // 这里就是处理注解的process函数 @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { // 创建动态代码,实际上就是创建一个String, 写入到文件里 // 然后文件会被解释为.class文件 StringBuilder builder = new StringBuilder() .append("package com.hxstrive.apt2;\n\n") .append("public class GeneratedClass {\n\n") .append("\tpublic String getMessage() {\n") .append("\t\treturn \""); // 获取所有被 MyAnnotation 修饰的代码元素 for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { String objectType = element.getSimpleName().toString(); builder.append(objectType).append(" exists!\\n"); } builder.append("\";\n") .append("\t}\n") .append("}\n"); // 将String写入并生成.class文件 try { JavaFileObject source = processingEnv.getFiler().createSourceFile( "com.hxstrive.apt2.GeneratedClass"); Writer writer = source.openWriter(); writer.write(builder.toString()); writer.flush(); writer.close(); } catch (IOException e) { // } return true; } }
(3)创建一个测试类 TestClass,并在方法上使用 @MyAnnotation 注解:
package com.hxstrive.apt2; /** * 测试类 * @author HuangXin * @since 1.0.0 */ public class TestClass { @MyAnnotation("Hello, Annotation Processing!") public void testMethod() { System.out.println("This is a test method."); } }
运行如下命令:
# 编译注解处理器 E:\demo\src\main\java>javac -encoding UTF-8 -cp .;./classes -d classes ./com/hxstrive/apt2/*.java # 触发注解处理器 E:\demo\src\main\java>javac -encoding UTF-8 -cp .;./classes -processor com.hxstrive.apt2.MyAnnotationProcessor ./com/hxstrive/apt2/TestClass.java
创建的动态代码如下图: