Vibesafe4j 使用 Annotation Processor 实现(编译时代码生成)
Vibesafe4j 默认在运行时生成代码,这种方式虽然灵活,但在生产环境中可能遇到一些问题:性能开销、调试困难、IDE 支持有限等。
Annotation Processor(注解处理器) 可以在编译时生成代码,解决这些问题。
编译时生成的优势
- ⚡ 性能更好:代码在编译时一次性生成,运行时无额外开销
- 🐛 易于调试:生成的源代码文件可以直接查看和调试
- 💡 IDE 友好:IDE 可以识别生成的代码,提供完整的代码补全
- ✅ 提前发现问题:编译时就能发现错误,不用等到运行时
- 🚀 生产环境友好:无需运行时编译器,部署更简单
什么时候用?
如果你需要:
- 更好的性能表现
- 可以查看和审查生成的代码
- 完整的 IDE 支持
- 适合生产环境使用
那么编译时生成是更好的选择。
什么是 Annotation Processor?
虽然 vibesafe4j 的当前实现使用运行时动态编译,但我们可以改用 Annotation Processor(注解处理器) 在编译时生成代码。Annotation Processor 是 Java 编译器的一个插件机制,允许在编译阶段处理注解并生成新的源代码文件。
这种方式相比运行时编译有以下优势:
Annotation Processor 的优势
- 编译时生成:代码在编译阶段生成,无需运行时编译器
- 性能更好:无需运行时编译和类加载开销
- 可调试性:生成的源代码文件可以直接查看和调试
- IDE 支持:更好的 IDE 集成和代码补全
- 类型安全:编译时就能发现类型错误
- 无运行时依赖:不需要
javac在运行时可用
实现架构设计
方案一:编译时调用 AI(推荐用于开发环境)
在编译时直接调用 AI API 生成代码。这需要 Annotation Processor 能够进行网络请求。
方案二:预生成代码(推荐用于生产环境)
使用 Gradle/Maven 插件在编译前调用 AI 生成代码,然后 Annotation Processor 读取生成的代码。
项目模块结构
如果采用 Annotation Processor 方式,建议将项目拆分为两个模块:
模块划分
vibesafe4j-annotations(注解模块)- 包含
@Func注解定义 - 轻量级,只包含注解接口
- 用户项目需要依赖此模块
- 包含
vibesafe4j-processor(处理器模块)- 包含 Annotation Processor 实现
- 包含 AI 代码生成器
- 只在编译时使用,不会打包到最终应用
这种模块化设计的优势:
- 依赖分离:注解模块轻量,处理器模块只在编译时需要
- 性能优化:运行时不需要加载 Processor 相关代码
- 清晰职责:注解和处理器职责分离,便于维护
注意:如果项目是单一模块,也可以将所有代码放在一个模块中,但需要确保 Processor 不会被打包到运行时依赖中。
完整实现代码
1. 修改 @Func 注解(支持编译时处理)
package vibesafe4j;
import java.lang.annotation.*;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.SOURCE) // 改为 SOURCE,编译时处理
@Documented
public @interface Func {
String value() default "";
/**
* 是否在编译时生成实现
* 如果为 false,则跳过该方法的代码生成
*/
boolean generate() default true;
}
2. 创建 Annotation Processor
package vibesafe4j.processor;
import com.google.auto.service.AutoService;
import vibesafe4j.Func;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
/**
* Annotation Processor for @Func annotation
* 在编译时扫描 @Func 注解并生成实现类
*/
@SupportedAnnotationTypes("vibesafe4j.Func")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(Processor.class)
public class FuncAnnotationProcessor extends AbstractProcessor {
private Messager messager;
private Filer filer;
// AI 客户端接口(需要在编译时可用)
private AiCodeGenerator aiCodeGenerator;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.messager = processingEnv.getMessager();
this.filer = processingEnv.getFiler();
// 初始化 AI 代码生成器
// 可以通过系统属性或配置文件配置 AI API
this.aiCodeGenerator = createAiCodeGenerator();
}
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
// 按接口分组处理方法
Map<TypeElement, List<ExecutableElement>> interfaceMethods = new HashMap<>();
// 扫描所有带 @Func 注解的方法
for (Element element : roundEnv.getElementsAnnotatedWith(Func.class)) {
if (element.getKind() == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement) element;
TypeElement enclosingInterface = (TypeElement) method.getEnclosingElement();
Func funcAnnotation = method.getAnnotation(Func.class);
if (funcAnnotation.generate()) {
interfaceMethods.computeIfAbsent(enclosingInterface, k -> new ArrayList<>())
.add(method);
}
}
}
// 为每个接口生成实现类
for (Map.Entry<TypeElement, List<ExecutableElement>> entry : interfaceMethods.entrySet()) {
TypeElement interfaceElement = entry.getKey();
List<ExecutableElement> methods = entry.getValue();
try {
generateImplementation(interfaceElement, methods);
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR,
"Failed to generate implementation for " + interfaceElement.getQualifiedName() + ": " + e.getMessage());
}
}
return true;
}
/**
* 生成接口实现类
*/
private void generateImplementation(TypeElement interfaceElement,
List<ExecutableElement> methods) throws IOException {
String packageName = getPackageName(interfaceElement);
String interfaceName = interfaceElement.getSimpleName().toString();
String implClassName = interfaceName + "Impl";
String qualifiedImplName = packageName.isEmpty()
? implClassName
: packageName + "." + implClassName;
// 生成源代码
StringBuilder sourceCode = new StringBuilder();
// Package 声明
if (!packageName.isEmpty()) {
sourceCode.append("package ").append(packageName).append(";\n\n");
}
// 导入语句
sourceCode.append("import java.util.*;\n");
sourceCode.append("import java.time.*;\n\n");
// 类声明
sourceCode.append("/**\n");
sourceCode.append(" * Auto-generated implementation of ").append(interfaceName).append("\n");
sourceCode.append(" * Generated by vibesafe4j Annotation Processor\n");
sourceCode.append(" */\n");
sourceCode.append("public class ").append(implClassName)
.append(" implements ").append(interfaceName).append(" {\n\n");
// 生成每个方法的实现
for (ExecutableElement method : methods) {
generateMethodImplementation(sourceCode, method);
}
sourceCode.append("}\n");
// 写入文件
JavaFileObject sourceFile = filer.createSourceFile(qualifiedImplName, interfaceElement);
try (Writer writer = sourceFile.openWriter()) {
writer.write(sourceCode.toString());
}
messager.printMessage(Diagnostic.Kind.NOTE,
"Generated implementation: " + qualifiedImplName);
}
/**
* 生成单个方法的实现
*/
private void generateMethodImplementation(StringBuilder sourceCode,
ExecutableElement method) {
Func funcAnnotation = method.getAnnotation(Func.class);
String prompt = buildPrompt(method, funcAnnotation.value());
// 调用 AI 生成代码
String methodBody = aiCodeGenerator.generateMethodBody(prompt, method);
// 方法签名
sourceCode.append(" @Override\n");
sourceCode.append(" public ");
// 返回类型
TypeMirror returnType = method.getReturnType();
sourceCode.append(getTypeName(returnType)).append(" ");
// 方法名
sourceCode.append(method.getSimpleName()).append("(");
// 参数列表
List<? extends VariableElement> parameters = method.getParameters();
for (int i = 0; i < parameters.size(); i++) {
VariableElement param = parameters.get(i);
if (i > 0) {
sourceCode.append(", ");
}
sourceCode.append(getTypeName(param.asType()))
.append(" ")
.append(param.getSimpleName());
}
sourceCode.append(") {\n");
// 方法体(AI 生成)
String indentedBody = indentMethodBody(methodBody);
sourceCode.append(indentedBody);
sourceCode.append(" }\n\n");
}
/**
* 构建发送给 AI 的 prompt
*/
private String buildPrompt(ExecutableElement method, String annotationValue) {
StringBuilder prompt = new StringBuilder();
prompt.append("Write a valid Java method body that implements the following signature:\n\n");
prompt.append("Method signature: ");
prompt.append(getTypeName(method.getReturnType())).append(" ");
prompt.append(method.getSimpleName()).append("(");
List<? extends VariableElement> params = method.getParameters();
for (int i = 0; i < params.size(); i++) {
if (i > 0) prompt.append(", ");
VariableElement param = params.get(i);
prompt.append(getTypeName(param.asType()))
.append(" ")
.append(param.getSimpleName());
}
prompt.append(")\n\n");
if (!annotationValue.isEmpty()) {
prompt.append("Requirements:\n");
prompt.append(annotationValue).append("\n\n");
}
prompt.append("Requirements:\n");
prompt.append("- Return only the method body code\n");
prompt.append("- Do not include the method signature\n");
prompt.append("- Do not include any comments or explanations\n");
prompt.append("- Use proper Java syntax\n");
return prompt.toString();
}
/**
* 创建 AI 代码生成器
* 可以通过系统属性配置
*/
private AiCodeGenerator createAiCodeGenerator() {
String apiKey = System.getProperty("vibesafe4j.ai.apiKey");
String apiUrl = System.getProperty("vibesafe4j.ai.apiUrl",
"https://api.openai.com/v1/chat/completions");
String model = System.getProperty("vibesafe4j.ai.model", "gpt-4");
if (apiKey == null || apiKey.isEmpty()) {
messager.printMessage(Diagnostic.Kind.WARNING,
"No AI API key configured. Using mock generator. " +
"Set -Avibesafe4j.ai.apiKey=your-key to enable AI code generation.");
return new MockAiCodeGenerator();
}
return new OpenAiCodeGenerator(apiKey, apiUrl, model);
}
// 辅助方法
private String getPackageName(TypeElement typeElement) {
Element packageElement = typeElement.getEnclosingElement();
while (packageElement != null && packageElement.getKind() != ElementKind.PACKAGE) {
packageElement = packageElement.getEnclosingElement();
}
return packageElement != null ? packageElement.toString() : "";
}
private String getTypeName(TypeMirror type) {
return type.toString();
}
private String indentMethodBody(String body) {
return body.lines()
.map(line -> " " + line)
.reduce((a, b) -> a + "\n" + b)
.orElse("");
}
}
3. AI 代码生成器接口和实现
package vibesafe4j.processor;
import javax.lang.model.element.ExecutableElement;
/**
* AI 代码生成器接口
*/
public interface AiCodeGenerator {
/**
* 根据 prompt 和方法签名生成方法体代码
*/
String generateMethodBody(String prompt, ExecutableElement method);
}
package vibesafe4j.processor;
import javax.lang.model.element.ExecutableElement;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
/**
* OpenAI API 实现
*/
public class OpenAiCodeGenerator implements AiCodeGenerator {
private final String apiKey;
private final String apiUrl;
private final String model;
private final HttpClient httpClient;
public OpenAiCodeGenerator(String apiKey, String apiUrl, String model) {
this.apiKey = apiKey;
this.apiUrl = apiUrl;
this.model = model;
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
}
@Override
public String generateMethodBody(String prompt, ExecutableElement method) {
try {
String requestBody = buildRequestBody(prompt);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString());
return parseResponse(response.body());
} catch (Exception e) {
throw new RuntimeException("Failed to generate code from AI", e);
}
}
private String buildRequestBody(String prompt) {
return String.format("""
{
"model": "%s",
"messages": [
{
"role": "system",
"content": "You are a Java code generator. Return only valid Java code, no explanations."
},
{
"role": "user",
"content": "%s"
}
],
"temperature": 0.3,
"max_tokens": 1000
}
""", model, prompt.replace("\"", "\\\""));
}
private String parseResponse(String jsonResponse) {
// 简化实现,实际应该使用 JSON 解析库
int start = jsonResponse.indexOf("\"content\":\"") + 11;
int end = jsonResponse.indexOf("\"", start);
String content = jsonResponse.substring(start, end);
return content.replace("\\n", "\n").replace("\\\"", "\"");
}
}
package vibesafe4j.processor;
import javax.lang.model.element.ExecutableElement;
/**
* Mock 实现,用于测试或当 AI API 不可用时
*/
public class MockAiCodeGenerator implements AiCodeGenerator {
@Override
public String generateMethodBody(String prompt, ExecutableElement method) {
// 返回一个简单的实现
return "throw new UnsupportedOperationException(\"Method not implemented\");";
}
}
4. Maven 配置
注意:
vibesafe4j-annotations和vibesafe4j-processor是推荐的模块化结构。如果项目是单一模块,可以将所有代码放在一个模块中,并相应调整依赖配置。
推荐的模块化结构:
<project>
<!-- ... -->
<dependencies>
<!-- Annotation Processor 依赖 -->
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
<!-- 注解模块:包含 @Func 注解定义 -->
<dependency>
<groupId>vibesafe4j</groupId>
<artifactId>vibesafe4j-annotations</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<!-- Processor 模块:包含 Annotation Processor 实现 -->
<path>
<groupId>vibesafe4j</groupId>
<artifactId>vibesafe4j-processor</artifactId>
<version>1.0.0</version>
</path>
<path>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<!-- 传递 AI API 配置 -->
<arg>-Avibesafe4j.ai.apiKey=${VIBESAFE4J_API_KEY}</arg>
<arg>-Avibesafe4j.ai.model=${VIBESAFE4J_MODEL:gpt-4}</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
模块说明:
vibesafe4j-annotations:包含@Func注解定义,运行时不需要,但编译时需要vibesafe4j-processor:包含 Annotation Processor 实现,只在编译时使用,不会打包到最终应用中
如果使用单一模块:
如果项目是单一模块结构,可以将 Processor 配置为同一个 artifact:
<annotationProcessorPaths>
<path>
<groupId>vibesafe4j</groupId>
<artifactId>vibesafe4j</artifactId>
<version>1.0.0</version>
</path>
</annotationProcessorPaths>
5. Gradle 配置
推荐的模块化结构:
dependencies {
// Annotation Processor
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
compileOnly 'com.google.auto.service:auto-service:1.1.1'
// vibesafe4j 注解模块
implementation 'vibesafe4j:vibesafe4j-annotations:1.0.0'
// vibesafe4j Processor 模块(只在编译时使用)
annotationProcessor 'vibesafe4j:vibesafe4j-processor:1.0.0'
}
tasks.withType(JavaCompile) {
options.compilerArgs += [
'-Avibesafe4j.ai.apiKey=' + (System.getenv('VIBESAFE4J_API_KEY') ?: ''),
'-Avibesafe4j.ai.model=' + (System.getenv('VIBESAFE4J_MODEL') ?: 'gpt-4')
]
}
如果使用单一模块:
dependencies {
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
// 单一模块时,使用同一个 artifact
implementation 'vibesafe4j:vibesafe4j:1.0.0'
annotationProcessor 'vibesafe4j:vibesafe4j:1.0.0'
}
6. 使用示例
接口定义保持不变:
package com.example;
import vibesafe4j.Func;
public interface Greeting {
@Func("""
return a greeting String
>>> greet("Alice")
'Hello, Alice!'
""")
String greet(String name);
}
编译后会自动生成 GreetingImpl.java:
package com.example;
/**
* Auto-generated implementation of Greeting
* Generated by vibesafe4j Annotation Processor
*/
public class GreetingImpl implements Greeting {
@Override
public String greet(String name) {
return "Hello, " + name + "!";
}
}
7. Spring Boot 集成(简化版)
package vibesafe4j.spring;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 自动配置:扫描生成的实现类并注册为 Bean
*/
@Configuration
@ConditionalOnClass(name = "vibesafe4j.Func")
public class Vibesafe4jAutoConfiguration {
// 由于实现类已经在编译时生成,可以直接扫描
// Spring 会自动发现并注册这些类
}
两种方案对比
| 特性 | 运行时编译(当前) | Annotation Processor(编译时) |
|---|---|---|
| 代码生成时机 | 运行时 | 编译时 |
| 性能 | 首次调用较慢 | 编译时一次性生成 |
| 运行时依赖 | 需要 javac | 无需编译器 |
| 可调试性 | 难以调试 | 可查看源代码 |
| IDE 支持 | 有限 | 完整支持 |
| AI 调用 | 运行时调用 | 编译时调用 |
| 离线编译 | 支持 | 需要网络(除非预生成) |
| 错误发现 | 运行时发现 | 编译时发现 |
混合方案:预生成 + Annotation Processor
结合两种方式的优势:
- 开发阶段:使用 Gradle/Maven 插件在编译前调用 AI 生成代码
- Annotation Processor:读取预生成的代码并生成实现类
- 生产环境:使用预生成的代码,无需 AI API
Gradle 插件示例
// build.gradle
plugins {
id 'java'
id 'vibesafe4j' version '1.0.0'
}
vibesafe4j {
apiKey = project.findProperty('vibesafe4j.apiKey') ?: System.getenv('VIBESAFE4J_API_KEY')
model = 'gpt-4'
outputDir = file('src/generated/vibesafe4j')
}
sourceSets {
main {
java {
srcDirs += 'src/generated/vibesafe4j'
}
}
}
实现总结
使用 Annotation Processor 实现 vibesafe4j 的主要改动:
- 注解保留策略:
@Retention(RetentionPolicy.SOURCE) - 创建 Processor:实现
AbstractProcessor接口 - 代码生成:使用
Filer.createSourceFile()生成源代码 - AI 集成:在编译时调用 AI API(或使用预生成代码)
- 构建配置:配置 Annotation Processor 路径和参数
这种方式更适合生产环境,提供了更好的性能和可维护性。
常见问题(FAQ)
Q: Annotation Processor 和运行时编译有什么区别?
A: Annotation Processor 在编译时生成代码,性能更好,可调试性强;运行时编译在程序运行时生成代码,更灵活但性能较差。
Q: 如何在编译时调用 AI API?
A: 可以在 Annotation Processor 中使用 HTTP 客户端调用 AI API,或使用预生成代码方案。
Q: vibesafe4j-annotations 和 vibesafe4j-processor 是两个独立的项目吗?
A: 这是推荐的模块化结构。vibesafe4j-annotations 包含注解定义,vibesafe4j-processor 包含处理器实现。如果项目是单一模块,也可以将两者合并,但需要确保 Processor 不会被打包到运行时依赖中。
Q: 生成的代码在哪里?
A: 生成的代码通常在 target/generated-sources/annotations(Maven)或 build/generated/sources/annotationProcessor(Gradle)目录。
Q: IDE 能识别生成的代码吗?
A: 可以,现代 IDE(IntelliJ IDEA、Eclipse)都能自动识别和索引生成的代码。
Q: 如何调试 Annotation Processor?
A: 可以使用 messager.printMessage() 输出调试信息,或使用 IDE 的远程调试功能。
相关文章
- Vibesafe4j 详细介绍 - 了解 Vibesafe4j 框架基础
- Spring AI 介绍 - Spring AI 框架使用指南
参考资源
- Vibesafe4j 项目仓库 - GitHub 源代码和示例
- Java Annotation Processor 官方文档 - Oracle 官方文档
- Google Auto Service - Auto Service 库文档
- Lombok 实现参考 - 优秀的 Annotation Processor 实现示例
- Java Annotation Processing 教程 - Baeldung 教程
本文详细介绍了如何使用 Annotation Processor 实现 vibesafe4j 的编译时代码生成功能。通过编译时生成代码,可以获得更好的性能和可维护性。
