Java反思:如何获得评论?

时间:2018-03-13 14:53:33

标签: java reflection javaparser

我在Java解析方面遇到了一些困难。我需要以某种方式通过反射获得类,字段,方法等的注释。

我找到了JavaParser,看起来它可以引出评论,但我还没有得到如何做,因为所有的例子只是解析给定的字符串。我发现TypeSolver可以采用Canonical名称,但看起来它无法处理评论。

我的问题是,如果我只有Class<?>,并且该项目还有一些其他jar's也应该被反省,那么如何找到评论。通过调试我看到了原始的源代码,看起来有可能以某种方式做到 感谢。

P.S。我有源代码,我需要将Class<?>与源代码匹配,然后通过JavaParser提取评论

5 个答案:

答案 0 :(得分:1)

首先,您不能使用反射直接获取注释,也不能通过使用读取“ .class”文件的库获取注释。该信息不在“ .class”文件中,并且反射仅知道有关信息的信息,可以从那里直接获得。

正如人们指出的那样,只有拥有源代码,您才能获得注释。而且,如果您有源代码文件,则应该可以使用JavaParser或(可能)其他库,...或编写自己的解析器来提取注释。

问题将是从Class对象映射到相应的源代码文件。让我们假设您有多个源树,它们对应于应用程序的类路径上的多个JAR。您将需要:

  • 类路径上每个JAR或目录的URI,
  • 从每个URI到对应的源树的映射。

方法是:

  1. Class对象获取完全限定的类名。
  2. 将类名映射到相对的Java源路径;例如foo.bar.Baz将成为foo/bar/Baz.java
  3. 使用clazz.getProtectionDomain().getCodeSource().getLocation().toURI()从加载类的位置获取URI。
  4. 使用您的映射将URI映射到相应的源树。
  5. 解析相对于源树根的相对路径。
  6. 打开源文件。

以上某些步骤可能会出现问题。例如:

  • 在步骤2中,您需要处理嵌套类,
  • 在步骤3中,getCodeSource()可以返回null
  • 在第3步中,生成的URI可能有一个奇怪的协议,
  • 如果您的映射不完整,则第4步可能会失败,
  • 如果您的源代码未批处理您正在执行的代码,则步骤5可能会失败。

打开源文件后,您将构建一个Reader并使用所选的解析器来解析源代码。


如果您的项目是“绿色领域”项目,则定义自定义注释类型(保留==运行时)并将注释转换为注释可能会更简单。这些注释可以简单,快速地提取出来,而上面没有任何可能的故障模式。


由于所有[JavaParser]示例都只是解析给定的字符串,所以我没有怎么做。

javadoc显示您可以使用JavaParser实例来解析FileInputStreamReaderString

答案 1 :(得分:0)

我怀疑注释包含在已编译的代码中 - 所以没有办法通过反射来实现。最近的工具是XDoclet-1/2,它解析了javadoc标签并用它们来生成其他东西(以及这个灵感注释) - 但这个工具已经过时而且不再支持了

答案 2 :(得分:0)

你不能。

Bytecode在原始源代码中不包含任何内联或JavaDoc格式的注释,因为它们在编译阶段被删除。

如果您需要以某种方式将评论转移到Bytecode,请考虑使用Java Annotations代替。

答案 3 :(得分:0)

如果您有源代码,则可能是JAR文件的形式。将源文件放在JAR文件中非常容易,因为该类提供了包和本地名称。您必须考虑嵌套类的情况,但实际上很容易实现。

找到源文件后,可以使用JavaParser轻松解析它并检索注释:

var il = ...;
il.Body.ExceptionHandlers.Remove(ExceptionHandler handler);

答案 4 :(得分:-1)

您应该创建注释类并为您的需求获取价值。例如:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Report {
    String value();
}



public class ReportClass{
    @Report("this is comment")
    private String atmLastTrxAmount;
}



for (Field declaredField : ReportClass.class.getDeclaredFields()) {
    declaredField.setAccessible(true);
    String relatedFieldComment = declaredField.getAnnotation(Report.class).value();
    ...
}