java冷知识:javac AbstractProcessor详解

网友投稿 238 2022-11-24

java冷知识:javac AbstractProcessor详解

目录它可以做什么?ProcessorAbstractProcessor源码google的 auto-servicejavapoet你喜欢的lombok实现原理是怎样的呢?

它可以做什么?

它做的事情当然是生成新类或修改原始的类,比如你遇到这样的情况下就可以使用:

反射好慢,曾见过一个大厂大量是Gson,由于Gson序列化时大量使用了反射,每一个field,每一个get、set都需要用反射,由此带来了性能问题。解决方法就是使用它尽量减少反射(替换成jsONObject)

生成代码,只要是有注解的地方都可以读取,总之很多(有些android orm框架)

Processor

javax.annotation.processing.Processor 这个接口将提供注解处理,它遵循SPI规约进行拓展,jdk默认就有很多处理器的实现。

AbstractProcessor

注解处理器是最重要的拓展处理类了。

注意:请确认JAVA的环境变量已经配置成功,并且把tools.jar(它源于此包)加入到自己电脑的环境变量中

源码

重点关注process方法

// 源于javax.annotation.processing;

public abstract class AbstractProcessor implements Processor {

// 集合中指定支持的注解类型的名称(这里必须时完整的包名+类名)

public Set getSupportedAnnotationTypes() {

SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);

if (sat == null) {

if (isInitialized())

processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,

"No SupportedAnnotationTypes annotation " +

"found on " + this.getClass().getName() +

", returning an empty set.");

return Collections.emptySet();

}

else

return arrayToSet(sat.value());

}

// http://指定当前正在使用的Java版本

public SourceVersion getSupportedSourceVersion() {

SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class);

SourceVersion sv = null;

if (ssv == null) {

sv = SourceVersion.RELEASE_6;

if (isInitialized())

processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,

"No SupportedSourceVersion annotation " +

"found on " + this.getClass().getName() +

", returning " + sv + ".");

} else

sv = ssv.value();

return sv;

}

// 初始化处理器

public synchronized void init(ProcessingEnvironment processingEnv) {

if (initialized)

throw new IllegalStateException("Cannot call init more than once.");

Objects.requireNonNull(processingEnv, "Tool provided null ProcessingEnvironment");

this.processingEnv = processingEnv;

initialized = true;

}

/**

* 这些注解是否由此 Processor 处理,该方法返回ture表示该注解已经被处理, 后续不会再有其他处理器处理; 返回false表示仍可被其他处理器处理

*/

public abstract boolean process(Set extends TypeElement> annotations,

RoundEnvironment roundEnv);

}

实现一个打印可以API的功能

由于本人是maven环境,以此展开讲

org.apache.maven.plugins

maven-compiler-plugin

1.8

1.8

步骤1:实现一个注解处理器

@Retention(RetentionPolicy.SOURCE)

@Target({ElementType.TYPE, ElementType.METHOD})

public @interface ApiAnnotation {

String author() default "alex.chen";

String datejoUqcf();

int version() default 1;

}

@SupportedAnjoUqcfnotationTypes({"com.kxtx.annotation.ApiAnnotation"})

@SupportedSourceVersion(SourceVersion.RELEASE_8)

//@AutoService(Processor.class)

public class MyProcessor extends AbstractProcessor {

//类名的前缀、后缀

public static final String SUFFIX = "AutoGenerate";

public static final String PREFIX = "My_";

@Override

public boolean process(Set extends TypeElement> annotations, RoundEnvironment env) {

Messager messager = processingEnv.getMessager();

for (TypeElement typeElement : annotations) {

for (Element e : env.getElementsAnnotatedWith(typeElement)) {

//打印

messager.printMessage(Diagnostic.Kind.WARNING, "Printing:" + e.toString());

messager.printMessage(Diagnostic.Kind.WARNING, "Printing:" + e.getSimpleName());

messager.printMessage(Diagnostic.Kind.WARNING, "Printing:" + e.getEnclosedElements().toString());

//获取注解

ApiAnnotation annotation = e.getAnnotation(ApiAnnotation.class);

//获取元素名并将其首字母大写

String name = e.getSimpleName().toString();

char c = Character.toUpperCase(name.charAt(0));

name = String.valueOf(c + name.substring(1));

//包裹注解元素的元素, 也就是其父元素, 比如注解了成员变量或者成员函数, 其上层就是该类

Element enclosingElement = e.getEnclosingElement();

//获取父元素的全类名,用来生成报名

String enclosingQualifiedname;

if (enclosingElement instanceof PackageElement) {

enclosingQualifiedname = ((PackageElement) enclosingElement).getQualifiedName().toString();

} else {

enclosingQualifiedname = ((TypeElement) enclosingElement).getQualifiedName().toString();

}

try {

//生成包名

String generatePackageName = enclosingQualifiedname.substring(0, enclosingQualifiedname.lastIndexOf("."));

// 生成的类名

String genarateClassName = PREFIX + enclosingElement.getSimpleName() + SUFFIX;

//创建Java 文件

JavaFileObject f = processingEnv.getFiler().createSourceFile(genarateClassName);

// 在控制台输出文件路径

messager.printMessage(Diagnostic.Kind.WARNING, "Printing: " + f.toUri());

Writer w = f.openWriter();

try {

PrintWriter pw = new PrintWriter(w);

pw.println("package " + generatePackageName + ";");

pw.println("\npublic class " + genarateClassName + " { ");

pw.println("\n /** 打印值 */");

pw.println(" public static void print" + name + "() {");

pw.println(" // 注解的父元素: " + enclosingElement.toString());

pw.println(" System.out.println(\"代码生成的路径: " + f.toUri() + "\");");

pw.println(" System.out.println(\"注解的元素: " + e.toString() + "\");");

pw.println(" System.out.println(\"注解的版本: " + annotation.version() + "\");");

pw.println(" System.out.println(\"注解的日期: " + annotation.date() + "\");");

pw.println(" }");

pw.println("}");

pw.flush();

} finally {

w.close();

}

} catch (IOException e1) {

processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,

e1.toString());

}

}

}

return true;

}

}

步骤2:配置一个spi,在resources目录新建META-INF/services/javax.annotation.processing.Processor,内容为MyProcessor类全名。

步骤3:在另一个项目中使用@ApiAnnotation就会发现生成了一个新My_feignAutoGenerate.class文件:

public class My_feignAutoGenerate {

public My_feignAutoGenerate() {

}

public static void prinjoUqcftStartUp() {

System.out.println("代码生成的路径: file:/C:/Users/Administrator/Desktop/feign-async-master/target/generated-sources/annotations/My_feignAutoGenerate.java");

System.out.println("注解的元素: com.github.feign.StartUp");

System.out.println("注解的版本: 1");

System.out.println("注解的日期: 2019-03-6");

}

}

到这里基本上已经演示完了。

google的 auto-service

com.google.auto.service

auto-service

1.0-rc2

这个类库非常有用,它非常简单,使用@AutoService(Processor.class)会基于该接口和注解的类上自动帮我们生成META-INF/services下对应spi文件。它实现的原理就是通过注解处理器。

javapoet

有没有觉得上面pw.println("package " + generatePackageName + ";");这样的代码很痛苦啊?

JavaPoet is a Java API for generating .java source files.

package com.example.helloworld;

public final class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello, JavaPoet!");

}

}

MethodSpec main = MethodSpec.methodBuilder("main")

.addModifiers(Modifier.PUBLIC, Modifier.STATIC)

.returns(void.class)

.addParameter(String[].class, "args")

.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")

.build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")

.addModjoUqcfifiers(Modifier.PUBLIC, Modifier.FINAL)

.addMethod(main)

.build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)

.build();

javaFile.writeTo(System.out);

你喜欢的lombok实现原理是怎样的呢?

lombok(用来帮助开发人员消除 Java 对象 的冗长),非常好用

里面源码就不再介绍了!!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:适合高温环境应用的AD7981数据采集系统设计
下一篇:Hadoop大数据——mapreduce的secondary排序机制
相关文章

 发表评论

暂时没有评论,来抢沙发吧~