Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以编程方式编辑java源文件_Java_Reflection_Abstract Syntax Tree - Fatal编程技术网

以编程方式编辑java源文件

以编程方式编辑java源文件,java,reflection,abstract-syntax-tree,Java,Reflection,Abstract Syntax Tree,我正在寻找一种无需使用不稳定的正则表达式就可以通过编程方式编辑.java文件的方法。因为我正在编辑.java文件,而不是.class文件,所以我不需要任何字节码操作工具 我需要的是: 是独立于IDE的(因此没有ASTParser。我想在CI上自动化它,所以AST是不存在的,除非有独立版本) 允许我读取一个.java文件,向一个方法添加一个注释并保存它——因此单纯的源代码生成工具(我想到的是CodeModel)是不够的 不太复杂和/或专用于Java-因此没有ANTLR 简言之,要重现这个场景:

我正在寻找一种无需使用不稳定的正则表达式就可以通过编程方式编辑.java文件的方法。因为我正在编辑.java文件,而不是.class文件,所以我不需要任何字节码操作工具

我需要的是:

  • 是独立于IDE的(因此没有ASTParser。我想在CI上自动化它,所以AST是不存在的,除非有独立版本)
  • 允许我读取一个.java文件,向一个方法添加一个注释并保存它——因此单纯的源代码生成工具(我想到的是CodeModel)是不够的
  • 不太复杂和/或专用于Java-因此没有ANTLR
简言之,要重现这个场景:

File f = new File("path/to/.java");
CodeParser p = CodeParser.parse(f);
Method m = p.getMethods.get(0);
if (m.getBody().contains("abcdef") 
     && m.getAnnotation.getClass().equals(Test.class)){
   m.addAnnotation(MyAnnotation.class);
}
p.saveEdits(f);
我尝试过Java反射,但它做不到(而且因为它是字节码分析,所以无法解析方法体)。与java模型API类似。我试图让AST独立工作,但我失败了(也许有办法?)

如果绝对没有方法或工具可以做到这一点,那么有可能以一种独特而稳定的方式处理正则表达式吗?(即,除上述伪代码外,任何可能的Java源代码都不会成为操作的输入)。如果是这样,请给我举一个这样的例子


另外,我不需要编译它,在推送更改后,CI将为我进行编译。

查找javax.lang.model和注释处理API javax.annotation.processing。这允许您以标准化的方式向javac编译器编写插件,所有编译器都支持它。你可以在网上找到强调这一点的教程和讲座


有几个限制,例如,我不认为您可以重写文件的源代码,但是您可以使用注释生成新的文件(或类)。此外,您不能在方法体中对代码建模

您可以使用(PTS)可靠地执行此操作。这些是独立于IDE的

其中之一是我们的DMS软件再工程工具包。OP可以使用类似以下DMS元程序的代码来完成其特定任务:(未经测试,不处理所有边缘情况):

DMS的元编程语言看起来像Lisp,带有前缀运算符。(克服它:-) ParseFile读取源文件并构建一个AST,该AST驻留在parse_树中。 ScanTree扫描树,查找提供的谓词(“Registry:Pattern(.'any_method')为true的点,并返回匹配的子树或null。 Registry:PatternMatch检查指定树的根上的模式谓词是否为true。Registry:ApplyTransform应用源到源转换来修改树

这个元程序由一组命名模式支持,这使得在不知道树结构的每一个细节的情况下,在树上表达测试/转换变得很容易。 出于演示目的,这些内容过于简化:

 default domain Java~v7;

 pattern any_method(p: path_to_name, name: method_name, args: arguments,
                    b: body, a: annotations):declaration =
    " \p \name(\args) \a \b ";  -- doesn't handle non-functions but easily adjusted

 pattern TestClass(p: path_to_name, name: method_name, args: arguments,
                    b: body, a: annotations):declaration =
    " \p \name(\args) [Test.class] \b ";

 pattern abcdef_identifier():IDENTIFIER =
      "abcdef";

 rule insert_MyAnnotation(p: path_to_name, name: method_name, args: arguments,
                          b: body, a: annotations):declaration =
    " \p \name(\args) \a \b "
    ->
    " \p \name(\args) \a [myAnnotation] \b ";
引号是元引号;它们描述了模式匹配语言作为一个整体的语法和用目标语言编写的代码片段之间的界限(在本例中,是Java,因为域声明)语言语法,转义标识符表示对应于特定树节点类型的模式变量。您必须了解语法的大致结构才能编写这些语法,但请注意,我们并没有真正深入了解注释或任何内容是如何形成的

可以说,“any_方法”和“TestClass”模式可以合并为一个(事实上,只是TestClass模式本身,因为它是“any_方法”的纯粹专门化)

最后一条规则(其他规则是模式,仅用于匹配)说,“如果您看到X,请将其替换为Y”。特定规则所做的是使用一些注释列表对方法进行模式匹配,然后添加另一个注释


这是实现可靠程序转换的方法。如果您不想使用DMS(商业产品),查看维基百科页面,寻找替代方案。

同意,@ElliottFrisch将此问题指定为重复问题是完全错误的。首先,问题不同;OP没有询问任何关于Maven的问题。其次,答案不同;OP想知道他如何可靠地操纵AST,而另一个问题是does没有地址。使用正则表达式根本不可能可靠地修改源代码。作为一个基本缺陷,它们无法处理真实代码的嵌套结构;作为一个实际缺陷,您希望匹配代码结构,而不是代码文本。您需要的是程序转换系统(PTS):一个可以解析文本以生成AST的工具,能够检查和更改AST,以及将AST预打印回源代码的最终功能。请参阅以获取健壮的PTS列表。最后,即使使用PTS,也不要期望您的工作是琐碎的……好消息是,使用健壮的PTS,您可以对源代码进行相关的更改。我建议用一个例子补充一个较长的答案,如果是,将删除“重复”关于这个问题的名称。无法将其放入注释中。同时,请检查my bio.AFAIK ASTParser不依赖于Eclipse的GUI部分。它可以作为shwon单独使用:您的两个注释都很有趣。@Robert我将尝试一下,但如何在没有文档类的情况下将现有的.java文件输入AST?您知道吗r示例似乎从零开始生成一个文件。Ira Baxter-感谢您定义了我的问题域。一些谷歌搜索将我带到了这个页面:。我也将修补这些内容,尽管其中许多内容似乎已经过时。如果它不能对方法体的代码内容建模,该如何回答OP的查询m.getBody().contains(“abcdef”)?非常感谢:)别担心,我可以处理类似Lisp的语言和RPN(我自己是波兰人,嗯)。我不能测试你的解决方案(因为它是商业性的).你的解决方案与我所期望的实现ANTLR语法并从那里开始工作的方法非常相似。经过一天的研究,我发现问题有多复杂。我将你的答案标记为解决方案,因为
 default domain Java~v7;

 pattern any_method(p: path_to_name, name: method_name, args: arguments,
                    b: body, a: annotations):declaration =
    " \p \name(\args) \a \b ";  -- doesn't handle non-functions but easily adjusted

 pattern TestClass(p: path_to_name, name: method_name, args: arguments,
                    b: body, a: annotations):declaration =
    " \p \name(\args) [Test.class] \b ";

 pattern abcdef_identifier():IDENTIFIER =
      "abcdef";

 rule insert_MyAnnotation(p: path_to_name, name: method_name, args: arguments,
                          b: body, a: annotations):declaration =
    " \p \name(\args) \a \b "
    ->
    " \p \name(\args) \a [myAnnotation] \b ";