我正在寻找一种方法来编辑。java文件编程不诉诸于不稳定的RegExes。因为我正在编辑.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将为我做。
您可以使用程序转换系统(PTS)可靠地做到这一点。
其中之一是我们的DMS软件再造工具包。OP可以用类似以下DMS元程序的代码来完成他的特定任务:(未经测试,不处理所有边缘情况): (= parse_Tree (Domains:Java:Parser:ParseFile (. "path/to/.java")))
(local (= [method_tree AST:Node] (AST:ScanTree parse_Tree (Registry:Pattern (. `any_method'))
(ifthen (&& (~= method_tree AST:NullTree)
(Registry:PatternMatch method_tree (. `TestClass'))
(~= AST:NullTree (AST:ScanTree method_tree
(Registry:Pattern (. `abcdef_identifier'))))
(Registry:ApplyTransform method_tree (. `insert_MyAnnotation'))
)ifthen
)local
(Registry:PrettyPrintToFile method_tree (. "path/to/.java"))
DMS的元编程语言看起来像Lisp,带有前缀操作符。(克服它:-)ParseFile读取一个源文件,并构建一个AST,放在parse_Tree中。ScanTree扫描树,查找所提供的谓词("Registry:Pattern()")。' any_method'")为真,并返回匹配的子树或null。Registry:PatternMatch检查在指定树的根处模式谓词是否为真。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,因为有域声明)编写的代码片段之间的边界。元引号内是目标(Java)语言语法,带有表示与特定树节点类型对应的模式变量的转义标识符。要编写这些代码,您必须知道语法的大致结构,但请注意,我们并没有真正深入研究如何形成注释或其他内容的细节。
可以说,"any_method"one_answers"TestClass"模式可以合并为一个(实际上,只是TestClass模式本身,因为它是"any_method"的纯粹专门化)。
最后一个规则(其他是模式,仅用于匹配)表示,"如果您看到X,请将其替换为Y"。特定规则所做的是与带有一些注释列表的方法进行模式匹配,并添加另一个注释。
这是实现可靠程序转换的方法。如果您不想使用DMS(商业产品),请查看Wikipedia页面以获取替代方案。
查找javax.lang.model和注释处理API javax.annotation.processing。这允许您以标准化的方式为javac编译器编写插件,所有编译器都支持它。你可以在网上找到强调这一点的教程和演讲。
有一些限制,例如,我不认为您可以重写文件的源代码,但您可以生成带有注释的新文件(或类)。此外,您不能在方法体中对代码进行建模。