GraalProcessor.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package cn.binarywang.wx.graal;
  2. import lombok.Data;
  3. import lombok.extern.slf4j.Slf4j;
  4. import javax.annotation.processing.AbstractProcessor;
  5. import javax.annotation.processing.RoundEnvironment;
  6. import javax.annotation.processing.SupportedAnnotationTypes;
  7. import javax.annotation.processing.SupportedSourceVersion;
  8. import javax.lang.model.SourceVersion;
  9. import javax.lang.model.element.TypeElement;
  10. import javax.lang.model.type.DeclaredType;
  11. import javax.lang.model.type.TypeKind;
  12. import javax.lang.model.type.TypeMirror;
  13. import javax.lang.model.util.ElementFilter;
  14. import javax.tools.FileObject;
  15. import javax.tools.StandardLocation;
  16. import java.io.IOException;
  17. import java.io.Writer;
  18. import java.util.Set;
  19. import java.util.SortedSet;
  20. import java.util.TreeSet;
  21. /**
  22. * 目前仅仅处理@Data,且必须在lombok自己的processor之前执行,千万注意!!!!!
  23. *
  24. * @author outersky
  25. */
  26. @SupportedAnnotationTypes("lombok.Data")
  27. @SupportedSourceVersion(SourceVersion.RELEASE_7)
  28. public class GraalProcessor extends AbstractProcessor {
  29. private static final String REFLECTION_CONFIG_JSON = "reflection-config.json";
  30. private static final String NATIVE_IMAGE_PROPERTIES = "native-image.properties";
  31. private SortedSet<String> classSet = new TreeSet<>();
  32. private String shortestPackageName = null;
  33. @Override
  34. public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  35. for (TypeElement annotatedClass : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Data.class))) {
  36. registerClass(annotatedClass.getQualifiedName().toString());
  37. handleSuperClass(annotatedClass);
  38. }
  39. //只有最后一轮才可以写文件,否则文件会被重复打开,报错!
  40. if (!roundEnv.processingOver()) {
  41. return false;
  42. }
  43. // 如果没有文件要写,跳过
  44. if (classSet.isEmpty()) {
  45. return false;
  46. }
  47. writeFiles();
  48. //必须返回false,以便让lombok能继续处理。
  49. return false;
  50. }
  51. /**
  52. * 设置当前最短的package名称
  53. *
  54. * @param packageName 包名
  55. */
  56. private void setShortestPackageName(String packageName) {
  57. if (shortestPackageName == null) {
  58. shortestPackageName = packageName;
  59. } else if (packageName.length() < shortestPackageName.length()) {
  60. shortestPackageName = packageName;
  61. }
  62. }
  63. /**
  64. * 更加完整的类名来获取package名称
  65. *
  66. * @param fullClassName 完整的类名
  67. * @return package name
  68. */
  69. private String getPackageName(String fullClassName) {
  70. int last = fullClassName.lastIndexOf('.');
  71. if (last == -1) {
  72. return fullClassName;
  73. }
  74. return fullClassName.substring(0, last);
  75. }
  76. /**
  77. * 保存文件
  78. * META-INF/native-image/.../reflection-config.json
  79. * META-INF/native-image/.../native-image.properties
  80. */
  81. private void writeFiles() {
  82. String basePackage = shortestPackageName;
  83. String module;
  84. if (basePackage.contains(".")) {
  85. final int i = basePackage.lastIndexOf('.');
  86. module = basePackage.substring(i + 1);
  87. basePackage = basePackage.substring(0, i);
  88. } else {
  89. module = basePackage;
  90. }
  91. String path = "META-INF/native-image/" + basePackage + "/" + module + "/";
  92. String reflectFile = path + REFLECTION_CONFIG_JSON;
  93. String propsFile = path + NATIVE_IMAGE_PROPERTIES;
  94. try {
  95. FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", propsFile);
  96. try (Writer writer = fileObject.openWriter();) {
  97. writer.append("Args = -H:ReflectionConfigurationResources=${.}/" + REFLECTION_CONFIG_JSON);
  98. }
  99. } catch (IOException e) {
  100. e.printStackTrace();
  101. }
  102. try {
  103. FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", reflectFile);
  104. try (Writer writer = fileObject.openWriter();) {
  105. writer.write("[\n");
  106. boolean first = true;
  107. for (String name : classSet) {
  108. if (first) {
  109. first = false;
  110. } else {
  111. writer.write(",");
  112. }
  113. writer.write(assetGraalJsonElement(name));
  114. writer.append('\n');
  115. }
  116. writer.write("]");
  117. }
  118. } catch (IOException e) {
  119. e.printStackTrace();
  120. }
  121. }
  122. private String assetGraalJsonElement(String className) {
  123. return "{\n" +
  124. " \"name\" : \"" + className + "\",\n" +
  125. " \"allDeclaredFields\":true,\n" +
  126. " \"allDeclaredMethods\":true,\n" +
  127. " \"allDeclaredConstructors\":true,\n" +
  128. " \"allPublicMethods\" : true\n" +
  129. "}";
  130. }
  131. /**
  132. * 登记一个class
  133. *
  134. * @param className 完整的类名
  135. */
  136. private void registerClass(String className) {
  137. classSet.add(className);
  138. setShortestPackageName(getPackageName(className));
  139. }
  140. /**
  141. * 获取一个类型的所有的父类,并登记
  142. *
  143. * @param typeElement 类型元素
  144. */
  145. private void handleSuperClass(TypeElement typeElement) {
  146. TypeMirror superclass = typeElement.getSuperclass();
  147. if (superclass.getKind() == TypeKind.DECLARED) {
  148. TypeElement s = (TypeElement) ((DeclaredType) superclass).asElement();
  149. String sName = s.toString();
  150. // ignore java.**/javax.**
  151. if (sName.startsWith("java.") || sName.startsWith("javax.")) {
  152. return;
  153. }
  154. registerClass(sName);
  155. handleSuperClass(s);
  156. }
  157. }
  158. }