在运行时从注释处理器获取信息
Getting information from Annotation processor at runtime
我有一个工作的注释处理器,它收集带注释的 classes 的信息。编译期间一切都在那里。但我想在运行时访问这些结果。
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {
private final static List<TestInfo> tests = new ArrayList<>();
@Override
public Set getSupportedAnnotationTypes() {
return new LinkedHashSet() {
{
add(Annotation.class.getCanonicalName());
}
};
}
@Override
public boolean process(final Set<? extends TypeElement> annotations,
final RoundEnvironment env) {
System.out.println("Processing!");
if (!env.processingOver()) {
Set<? extends Element> rootE = env.getRootElements();
for (Element e : rootE) {
if (e.getKind() == ElementKind.CLASS) {
TestInfo t = new TestInfo(e.asType().toString());
for (Element se : e.getEnclosedElements()) {
if (se.getKind() == ElementKind.METHOD) {
t.addMethod(se.getSimpleName().toString());
}
}
getTests().add(t);
}
}
getTests().forEach(ti -> {
System.out.println(ti);
});
}
return false;
}
public static TypeElement findEnclosingTypeElement(Element e) {
while (e != null && !(e instanceof TypeElement)) {
e = e.getEnclosingElement();
}
return TypeElement.class.cast(e);
}
/**
* @return the tests
*/
public static List<TestInfo> getTests() {
return tests;
}
}
有没有办法在运行时检索结果? TestProcessor.getTests returns 一个空列表。
这是测试信息 class 仅供参考:
public class TestInfo {
private final String name;
private final List<String> methods = new ArrayList<>();
public TestInfo(String name) {
this.name = name;
}
public void addMethod(String m) {
getMethods().add(m);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the methods
*/
public List<String> getMethods() {
return methods;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append(methods.toString());
return sb.toString();
}
}
更新:注解标有保留运行时间。
查看 @RetentionPolicy
。我认为您想将其设置为 RUNTIME
。
注释处理在编译时。所以你无法在运行时间内获取信息。
直接的方法是在编译时将信息写成资源文件,在运行时读取。
这是我的例子:
注解:
@Retention(SOURCE)
@Target(TYPE)
public @interface Anno {
}
处理器:
@Override
public boolean processActual(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
try {
write(roundEnv);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void write(RoundEnvironment roundEnv) throws IOException, UnsupportedEncodingException {
Filer filer = processingEnv.getFiler();
FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "TestInfo");
OutputStream output = resource.openOutputStream();
PrintStream writer = new PrintStream(output, false, "UTF-8");
roundEnv.getElementsAnnotatedWith(Anno.class)
.stream()
.filter(e -> e.getKind() == ElementKind.CLASS)
.map(e -> e.asType().toString())
.forEach(writer::println);
writer.flush();
}
用户代码:
@Anno
public class Q48177784 {
public static final List<Class<?>> CLASSES;
static {
try {
URL resource = Q48177784.class.getClassLoader().getResource("TestInfo");
CLASSES = Files.readAllLines(Paths.get(resource.toURI()))
.stream()
.map(s -> {
try {
return Class.forName(s);
} catch (ClassNotFoundException e) {
throw new Error(e);
}
})
.collect(Collectors.toList());
} catch (Exception e) {
throw new Error(e);
}
}
public static void main(String[] args) {
System.out.println(CLASSES);
}
}
使用处理器构建后,运行 main
方法:
[class xdean.Whosebug.Q48177784]
对于您的情况,您唯一应该做的就是 serialize/deserialize 您的 TestInfo
我有一个工作的注释处理器,它收集带注释的 classes 的信息。编译期间一切都在那里。但我想在运行时访问这些结果。
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {
private final static List<TestInfo> tests = new ArrayList<>();
@Override
public Set getSupportedAnnotationTypes() {
return new LinkedHashSet() {
{
add(Annotation.class.getCanonicalName());
}
};
}
@Override
public boolean process(final Set<? extends TypeElement> annotations,
final RoundEnvironment env) {
System.out.println("Processing!");
if (!env.processingOver()) {
Set<? extends Element> rootE = env.getRootElements();
for (Element e : rootE) {
if (e.getKind() == ElementKind.CLASS) {
TestInfo t = new TestInfo(e.asType().toString());
for (Element se : e.getEnclosedElements()) {
if (se.getKind() == ElementKind.METHOD) {
t.addMethod(se.getSimpleName().toString());
}
}
getTests().add(t);
}
}
getTests().forEach(ti -> {
System.out.println(ti);
});
}
return false;
}
public static TypeElement findEnclosingTypeElement(Element e) {
while (e != null && !(e instanceof TypeElement)) {
e = e.getEnclosingElement();
}
return TypeElement.class.cast(e);
}
/**
* @return the tests
*/
public static List<TestInfo> getTests() {
return tests;
}
}
有没有办法在运行时检索结果? TestProcessor.getTests returns 一个空列表。
这是测试信息 class 仅供参考:
public class TestInfo {
private final String name;
private final List<String> methods = new ArrayList<>();
public TestInfo(String name) {
this.name = name;
}
public void addMethod(String m) {
getMethods().add(m);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the methods
*/
public List<String> getMethods() {
return methods;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append(methods.toString());
return sb.toString();
}
}
更新:注解标有保留运行时间。
查看 @RetentionPolicy
。我认为您想将其设置为 RUNTIME
。
注释处理在编译时。所以你无法在运行时间内获取信息。
直接的方法是在编译时将信息写成资源文件,在运行时读取。
这是我的例子:
注解:
@Retention(SOURCE)
@Target(TYPE)
public @interface Anno {
}
处理器:
@Override
public boolean processActual(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
try {
write(roundEnv);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void write(RoundEnvironment roundEnv) throws IOException, UnsupportedEncodingException {
Filer filer = processingEnv.getFiler();
FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "TestInfo");
OutputStream output = resource.openOutputStream();
PrintStream writer = new PrintStream(output, false, "UTF-8");
roundEnv.getElementsAnnotatedWith(Anno.class)
.stream()
.filter(e -> e.getKind() == ElementKind.CLASS)
.map(e -> e.asType().toString())
.forEach(writer::println);
writer.flush();
}
用户代码:
@Anno
public class Q48177784 {
public static final List<Class<?>> CLASSES;
static {
try {
URL resource = Q48177784.class.getClassLoader().getResource("TestInfo");
CLASSES = Files.readAllLines(Paths.get(resource.toURI()))
.stream()
.map(s -> {
try {
return Class.forName(s);
} catch (ClassNotFoundException e) {
throw new Error(e);
}
})
.collect(Collectors.toList());
} catch (Exception e) {
throw new Error(e);
}
}
public static void main(String[] args) {
System.out.println(CLASSES);
}
}
使用处理器构建后,运行 main
方法:
[class xdean.Whosebug.Q48177784]
对于您的情况,您唯一应该做的就是 serialize/deserialize 您的 TestInfo