自动生成Java源代码

我正在寻找一种方法,根据类中定义的字段,自动为现有Java源代码文件中的新方法生成源代码。

本质上,我希望执行以下步骤:

  1. 阅读并解析SomeClass.java
  2. 迭代源代码中定义的所有字段
  3. 添加源代码方法someMethod()
  4. 保存SomeClass.java (理想情况下,保留现有代码的格式)

哪些工具和技术最适合实现这一目标?

编辑

我不想在运行时生成代码; 我想扩充现有的Java 源代码

使用自动生成的代码修改相同的java源文件是维护噩梦。 考虑生成一个扩展当前类的新类,并添加所需的方法。 使用reflection从用户定义的类中读取并为自动生成类创建速度模板。 然后为每个用户定义的类生成其扩展类。 在构建生命周期中集成代码生成阶段。

或者您可以使用“字节码增强”技术来增强类,而无需修改源代码。

更新:

  1. 混合自动生成的代码总是会冒着将来修改它的风险,只是为了调整一个小的行为。 这只是下一次构建的问题,当这种变化将会丢失时。
  2. 您必须完全依赖自动生成源代码之上的注释来阻止开发人员这样做。
  3. 版本控制 – 假设您更新了someMethod()的模板,现在您的所有源文件版本都将更新,即使源更新是自动生成的。 你会看到多余的历史。

你想要的是程序转换系统。

好的有你所关心语言的解析器,构建代表解析代码程序的AST,为你提供分析和修改AST的访问权限,并且可以从AST重新生成源文本。 你对“扫描字段”的评论只是代表程序的AST的一种遍历。 对于您生成的每个有趣的分析结果,您希望对AST进行更改,可能在其他位置,但仍然在AST中。 在完成所有chagnes后,您需要使用注释(最初输入或在新代码中构建)重新生成文本。

有几种工具专门用于Java。

Jackpot提供了一个解析器,构建了AST,并允许您编写Java过程来对树进行所需的操作。 好处:简单概念。 缺点:你写了很多Java代码来爬树/砍伐树木而不是你期望的。 Jackpot仅适用于Java。

Stratego和TXL解析您的代码,构建AST,并让您编写“surce-to-source”转换(使用目标语言的语法,例如本例中的Java)来表达模式和修复。 其他好消息:您可以定义您喜欢的任何编程语言,作为要处理的目标语言,并且这两种语言都具有Java定义。 但他们在分析方面很薄弱:通常需要符号表和数据流分析才能真正进行所需的分析和更改。 并且他们坚持认为一切都是重写规则,无论是否有助于你; 这有点像坚持你只需要工具箱中的锤子; 毕竟,一切都可以像钉子一样对待,对吧?

我们的DMS软件再造工具包允许定义一个abitrary目标语言(并有许多预定义语言, 包括Java ),包括Stratego,TXL的所有源到源转换function,Jackpot的程序function,并另外提供符号表,控制和数据流分析信息。 编译人员告诉我们这些东西对于构建强大的编译器(=“分析+优化+优化”)是必要的,并且由于完全相同的原因,它也适用于代码生成系统。 使用此方法,您可以生成代码并在您具备相关知识的范围内对其进行优化。 类似于序列化思想的一个例子是为指定的XML DTD生成快速XML读取器和编写器; 我们已经使用DMS for Java和COBOL完成了这项工作。

DMS已被用于读取/修改/写入多种源文件。 可以在本技术论文中找到一个很好的例子,使这些想法变得清晰,该技术论文展示了如何修改代码以插入仪器探针: 分支覆盖变得容易 。 可以在如何使用相同的思想转换代数中找到一个更简单但更完整的定义应用于它的任意lanauges和变换的示例。

看看Java Emitter模板 。 它们允许您使用标记语言创建Java源文件。 它类似于如何使用脚本语言来吐出HTML,除非您吐出可编译的源代码。 JET的语法与JSP非常相似,因此不太难以接受。 然而,对于你想要完成的事情,这可能是一种过度杀伤力。 如果您决定沿着这条路走下去,这里有一些资源:

您可以使用cglib在运行时生成代码。

迭代字段并定义someMethod是一个非常模糊的问题陈述,因此很难给出一个非常有用的答案,但Eclipse的重构支持提供了一些很好的工具。 它将为您提供初始化所选定义成员集的构造函数,并且它还将为您定义toString方法。

我不知道你想要考虑的其他someMethod(),但是有一个开始。

我非常谨慎地将生成的代码注入包含手写代码的文件中。 应该将手写代码检入修订控制,但生成的代码不应该; 代码生成应该作为构建过程的一部分完成。 您必须构建构建过程,以便为每个文件创建临时副本,将生成的源代码注入其中,然后编译结果,而不触及开发人员处理的原始源文件。

Antlr是一个非常棒的工具,可以非常轻松地将Java源代码转换为Java源代码。