javax.lang.model完整教程:掌握Java语言模型与编译时处理
javax.lang.model是Java语言模型的核心包,专门用于编译时代码处理和分析。本文通过四个实用场景详细解析其核心组件:Element、TypeMirror、AnnotationMirror等接口的使用方法,包含完整的元素遍历、类型信息处理、注解处理器实现和访问者模式应用代码示例,帮助开发者掌握Java编译时处理技术,提升代码分析和生成能力。
javax.lang.model 是 Java 语言模型的核心包,提供了一套用于建模 Java 编程语言元素的接口和类。它主要用于编译时处理,如注解处理器(Annotation Processors)和代码分析工具。
主要组件
核心接口
Element - 表示程序元素(包、类、方法、字段等)
TypeMirror - 表示 Java 类型
AnnotationMirror - 表示注解
ExecutableElement - 表示方法、构造函数等可执行元素
示例代码
1. 基本元素遍历
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.*;
import javax.tools.Diagnostic;
import java.util.Set;
@SupportedAnnotationTypes("*") // 处理所有注解
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class ElementProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
Elements elementUtils = processingEnv.getElementUtils();
Types typeUtils = processingEnv.getTypeUtils();
// 遍历所有根元素
for (Element element : roundEnv.getRootElements()) {
processElement(element, 0);
}
return false; // 不声明处理了注解,让其他处理器继续
}
private void processElement(Element element, int depth) {
String indent = " ".repeat(depth);
// 打印元素信息
processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE,
indent + "Element: " + element.getKind() +
" - " + element.getSimpleName() +
" - " + elementUtils.getBinaryName((TypeElement)element)
);
// 处理注解
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE,
indent + " Annotation: @" + annotation.getAnnotationType()
);
}
// 递归处理子元素
for (Element enclosed : element.getEnclosedElements()) {
processElement(enclosed, depth + 1);
}
}
}2. 类型信息处理
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
public class TypeAnalyzer {
private final Types typeUtils;
private final Elements elementUtils;
public TypeAnalyzer(Types typeUtils, Elements elementUtils) {
this.typeUtils = typeUtils;
this.elementUtils = elementUtils;
}
public void analyzeType(TypeElement typeElement) {
System.out.println("=== 分析类型: " + typeElement.getQualifiedName() + " ===");
// 获取类型镜像
TypeMirror typeMirror = typeElement.asType();
System.out.println("类型: " + typeMirror);
System.out.println("种类: " + typeMirror.getKind());
// 检查是否为接口
System.out.println("是否为接口: " + typeElement.getKind().isInterface());
// 获取父类
TypeMirror superclass = typeElement.getSuperclass();
if (superclass.getKind() != TypeKind.NONE) {
System.out.println("父类: " + superclass);
}
// 获取实现的接口
System.out.println("实现的接口:");
for (TypeMirror interfaceType : typeElement.getInterfaces()) {
System.out.println(" - " + interfaceType);
}
// 分析类型参数
analyzeTypeParameters(typeElement);
// 分析方法
analyzeMethods(typeElement);
}
private void analyzeTypeParameters(TypeElement typeElement) {
if (!typeElement.getTypeParameters().isEmpty()) {
System.out.println("类型参数:");
for (TypeParameterElement typeParam : typeElement.getTypeParameters()) {
System.out.println(" - " + typeParam.getSimpleName());
for (TypeMirror bound : typeParam.getBounds()) {
System.out.println(" 边界: " + bound);
}
}
}
}
private void analyzeMethods(TypeElement typeElement) {
System.out.println("方法:");
for (Element enclosed : typeElement.getEnclosedElements()) {
if (enclosed.getKind() == ElementKind.METHOD) {
ExecutableElement method = (ExecutableElement) enclosed;
System.out.println(" - " + method.getSimpleName());
// 返回类型
System.out.println(" 返回类型: " + method.getReturnType());
// 参数
if (!method.getParameters().isEmpty()) {
System.out.println(" 参数:");
for (VariableElement param : method.getParameters()) {
System.out.println(" " + param.getSimpleName() +
" : " + param.asType());
}
}
// 修饰符
System.out.println(" 修饰符: " + method.getModifiers());
}
}
}
}3. 注解处理器示例
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.tools.Diagnostic;
import java.util.Set;
@SupportedAnnotationTypes("com.example.Validate")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class ValidationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(Validate.class)) {
processValidatedElement(element);
}
return true;
}
private void processValidatedElement(Element element) {
Validate validate = element.getAnnotation(Validate.class);
if (element.getKind() == ElementKind.FIELD) {
VariableElement field = (VariableElement) element;
// 检查字段类型是否匹配验证规则
TypeMirror fieldType = field.asType();
if (validate.notNull() && isNullableType(fieldType)) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
"字段 '" + field.getSimpleName() + "' 标记为 @Validate(notNull=true) " +
"但类型可能是可空的: " + fieldType,
field
);
}
if (validate.min() > 0 && isNumericType(fieldType)) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE,
"数值字段 '" + field.getSimpleName() + "' 有最小值限制: " + validate.min(),
field
);
}
}
}
private boolean isNullableType(TypeMirror type) {
// 检查类型是否可能是可空的(简化实现)
return type.getKind() == TypeKind.DECLARED &&
!type.toString().startsWith("java.util.Optional");
}
private boolean isNumericType(TypeMirror type) {
String typeName = type.toString();
return typeName.equals("int") || typeName.equals("long") ||
typeName.equals("double") || typeName.equals("float") ||
typeName.equals("java.lang.Integer") || typeName.equals("java.lang.Long");
}
}
// 示例注解
@interface Validate {
boolean notNull() default false;
long min() default 0;
long max() default Long.MAX_VALUE;
}4. 元素访问者模式
import javax.lang.model.element.*;
import javax.lang.model.util.*;
public class CustomElementVisitor extends SimpleElementVisitor8<Void, Void> {
@Override
public Void visitType(TypeElement e, Void p) {
System.out.println("访问类型: " + e.getQualifiedName());
System.out.println(" 修饰符: " + e.getModifiers());
return super.visitType(e, p);
}
@Override
public Void visitExecutable(ExecutableElement e, Void p) {
System.out.println("访问方法: " + e.getSimpleName());
System.out.println(" 返回类型: " + e.getReturnType());
System.out.println(" 参数数量: " + e.getParameters().size());
return super.visitExecutable(e, p);
}
@Override
public Void visitVariable(VariableElement e, Void p) {
ElementKind kind = e.getKind();
if (kind == ElementKind.FIELD) {
System.out.println("访问字段: " + e.getSimpleName() + " : " + e.asType());
} else if (kind == ElementKind.PARAMETER) {
System.out.println("访问参数: " + e.getSimpleName() + " : " + e.asType());
}
return super.visitVariable(e, p);
}
@Override
public Void visitPackage(PackageElement e, Void p) {
System.out.println("访问包: " + e.getQualifiedName());
return super.visitPackage(e, p);
}
}
// 使用访问者
public class VisitorExample {
public static void analyzeElement(Element element) {
CustomElementVisitor visitor = new CustomElementVisitor();
element.accept(visitor, null);
}
}主要用途
1、注解处理器 - 在编译时处理注解
2、代码生成 - 基于代码分析生成新代码
3、静态分析 - 分析代码结构和依赖
4、文档生成 - 提取代码信息生成文档
5、框架开发 - 开发需要理解代码结构的框架
最后更新于3月前
本文由人工编写,AI优化,转载请注明原文地址: javax.lang.model使用详解:Java注解处理器与代码分析实战指南
推荐阅读
评论 (2)
发表评论
昵称:加载中...
小萌酱2025-12-08 16:41:42
这篇指南对javax.lang.model的讲解非常清晰,特别是示例代码部分很实用,帮我解决了注解处理器开发中的困惑。感谢作者的分享!
微笑向暖2025-11-17 16:18:46
很实用的javax.lang.model详解!示例代码对我理解注解处理器很有帮助,期待更多实际应用场景的分享。