Java注解处理与单元测试实践
立即解锁
发布时间: 2025-08-20 00:10:20 阅读量: 1 订阅数: 10 


Java编程思想:从入门到精通
# Java注解处理与单元测试实践
## 1. 使用apt处理注解
### 1.1 apt工具概述
apt是Sun推出的首个辅助处理注解的工具,虽然它还比较原始,但具备一些实用特性。与javac类似,apt是针对Java源文件而非编译后的类运行的。默认情况下,apt在处理完源文件后会对其进行编译。若在构建过程中自动创建新的源文件,此功能会很有用。实际上,apt会检查新创建的源文件是否包含注解,并在同一过程中对它们进行编译。
### 1.2 apt工作流程
当注解处理器创建新的源文件时,该文件会在新一轮处理中被检查是否包含注解。apt会持续进行多轮处理,直到不再创建新的源文件,然后编译所有源文件。
### 1.3 注解处理器与工厂
每个注解都需要自己的处理器,但apt工具可以轻松地将多个注解处理器组合在一起。它允许指定多个要处理的类,这比自己遍历File类要方便得多。还可以添加监听器,以接收注解处理轮次完成的通知。
apt通过使用AnnotationProcessorFactory为找到的每个注解创建合适的注解处理器。运行apt时,需要指定工厂类或能找到所需工厂的类路径。若未指定,apt会启动一个复杂的发现过程。
### 1.4 示例:提取接口注解
以下是一个用于从类中提取公共方法并将其转换为接口的注解:
```java
//: annotations/ExtractInterface.java
// APT-based annotation processing.
package annotations;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ExtractInterface {
public String value();
} ///:~
```
以下是一个包含公共方法的类,该方法可成为有用接口的一部分:
```java
//: annotations/Multiplier.java
// APT-based annotation processing.
package annotations;
@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 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));
}
} /* Output:
11*16 = 176
*///:~
```
接下来是用于提取接口的处理器:
```java
//: annotations/InterfaceExtractorProcessor.java
// APT-based annotation processing.
// {Exec: apt -factory
// annotations.InterfaceExtractorProcessorFactory
// Multiplier.java -s ../annotations}
package annotations;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import java.io.*;
import java.util.*;
public class InterfaceExtractorProcessor
implements AnnotationProcessor {
private final AnnotationProcessorEnvironment env;
private ArrayList<MethodDeclaration> interfaceMethods =
new ArrayList<MethodDeclaration>();
public InterfaceExtractorProcessor(
AnnotationProcessorEnvironment env) { this.env = env; }
public void process() {
for(TypeDeclaration typeDecl :
env.getSpecifiedTypeDeclarations()) {
ExtractInterface annot =
typeDecl.getAnnotation(ExtractInterface.class);
if(annot == null)
break;
for(MethodDeclaration m : typeDecl.getMethods())
if(m.getModifiers().contains(Modifier.PUBLIC) &&
!(m.getModifiers().contains(Modifier.STATIC)))
interfaceMethods.add(m);
if(interfaceMethods.size() > 0) {
try {
PrintWriter writer =
env.getFiler().createSourceFile(annot.value());
writer.println("package " +
typeDecl.getPackage().getQualifiedName() +";");
writer.println("public interface " +
annot.value() + " {");
for(MethodDeclaration m : interfaceMethods) {
writer.print(" public ");
writer.print(m.getReturnType() + " ");
writer.print(m.getSimpleName() + " (");
int i = 0;
for(ParameterDeclaration parm :
m.getParameters()) {
writer.print(parm.getType() + " " +
parm.getSimpleName());
if(++i < m.getParameters().size())
writer.print(", ");
}
writer.println(");");
}
writer.println("}");
writer.close();
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
}
} ///:~
```
处理器的`process()`方法完成所有工作。使用`MethodDeclaration`类及其`getModifiers()`方法来识别正在处理的类的公共方法(但忽略静态方法)。若找到任何公共方法,它们将被存储在`ArrayList`中,并用于在`.java`文件中创建新接口定义的方法。
最后是注解处理器工厂:
```java
//: annotations/InterfaceExtractorProcessorFactory.java
// APT-based annotation processing.
package annotations;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import java.util.*;
public class InterfaceExtractorProcessorFactory
implements AnnotationProcessorFactory {
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> atds,
AnnotationProcessorEnvironment env) {
return new InterfaceExtractorProcessor(env);
}
public Collection<String> supportedAnnotationTypes() {
return
Collections.singleton("annotations.ExtractInterface");
}
public Collection<String> supportedOptions() {
return Collections.emptySet();
}
} ///:~
```
### 1.5 生成的接口文件
运行上述代码后,生成的`IMultiplier.java`文件如下:
```java
package annotations;
public interface IMultiplier {
public int multiply (int x, int y);
}
```
该文件也会被apt编译,因此在同一目录下会看到`IMultiplier.class`文件。
### 1.6 流程图:apt处理注解流程
```mermaid
graph TD;
A[开始] --> B[指定要处理的源文件];
B --> C[注解处理器处理源文件];
C --> D{是否创建新源文件};
D -- 是 --> C;
D -- 否 --> E[编译所有源文件];
E --> F[结束];
```
## 2. 使用Visitor模式与apt
### 2.1 Visitor模式概述
处理注解可能会变得复杂。为防止在有更多注解和处理器时复杂度急剧增加,镜像API提供了支持Visitor设计模式的类。Visitor是一种经典的设计模式,它遍历数据结构或对象集合,并对每个对象执行操作。该操作与对象本身解耦,意味着可以在不向类定义中添加方法的情况下添加新操作。
### 2.2 示例:使用Visitor模式的SQL表生成器
```java
//: annotations/database/TableCreationProcessorFactory.java
// The database example using Visitor.
// {Exec: apt -factory
// annotations.database.TableCreationProcessorFactory
// database/Member.java -s database}
package annotations.database;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import com.sun.mirro
```
0
0
复制全文
相关推荐









