我正在寻找一种以编程方式编辑.java文件的方法,而不需要使用不稳定的RegExes。由于我正在编辑.java文件,而不是.class文件,我不想要任何字节码操作工具。
我需要一些东西:
简而言之,要重现这种情况:
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会为我做。
答案 0 :(得分:1)
您可以使用program transformation system(PTS)可靠地执行此操作。这些是独立于IDE的。
其中一个是我们的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读取源文件并构建一个驻留在parse_Tree中的AST。 ScanTree扫描树,查找提供的谓词("注册表:模式(.`any_method'")为真的点,并返回匹配的子树或null。 注册表:PatternMatch检查指定树的根处的模式谓词是否为true。注册表: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 ";
引号是 metaquotes ;它们描述了模式匹配语言整体语法与用目标语言编写的代码片段(在本例中为Java,因为域声明)之间的界限。元引号内部是目标(Java)语言语法,其中转义标识符表示与特定树节点类型对应的模式变量。你必须知道写这些语法的粗略结构,但请注意我们并没有真正深入研究注释或任何东西是如何形成的。
可以说是" any_method"和" TestClass"模式可以折叠成一个(事实上,只是TestClass模式本身,因为它是" any_method"的纯粹专业化。
最后的规则(其他模式,仅用于匹配)说,"如果您看到X,请将其替换为Y"。具体规则的作用是使用一些注释列表对方法进行模式匹配,然后添加另一个注释。
这是可靠程序转换的方法。如果您不想使用DMS(商业产品),请查看维基百科页面以了解替代方案。
答案 1 :(得分:-1)
查找javax.lang.model和注释处理API,javax.annotation.processing。这允许您以标准化方式将插件编写到javac编译器,所有编译器都支持它。您可以在线找到强调此内容的教程和讲座。
有一些限制,例如我认为您不能重写文件的来源,但您可以生成带有注释的新文件(或类)。此外,您无法在方法体内建模代码。