简体   繁体   English

自动生成Java源代码

[英]Automatically generating Java source code

I'm looking for a way to automatically generate source code for new methods within an existing Java source code file, based on the fields defined within the class. 我正在寻找一种方法,根据类中定义的字段,自动为现有Java源代码文件中的新方法生成源代码。

In essence, I'm looking to execute the following steps: 本质上,我希望执行以下步骤:

  1. Read and parse SomeClass.java 读取并解析SomeClass.java
  2. Iterate through all fields defined in the source code 迭代源代码中定义的所有字段
  3. Add source code method someMethod() 添加源代码方法someMethod()
  4. Save SomeClass.java (Ideally, preserving the formatting of the existing code) 保存SomeClass.java (理想情况下,保留现有代码的格式)

What tools and techniques are best suited to accomplish this? 哪些工具和技术最适合实现这一目标?

EDIT 编辑

I don't want to generate code at runtime; 我不想在运行时生成代码; I want to augment existing Java source code 我想扩充现有的Java 源代码

What you want is a Program Transformation system. 你想要的是一个程序转换系统。

Good ones have parsers for the language you care about, build ASTs representing the program for the parsed code, provide you with access to the AST for analaysis and modification, and can regenerate source text from the AST. 好的有你所关心语言的解析器,构建代表解析代码程序的AST,为你提供分析和修改的AST,并可以从AST重新生成源文本。 Your remark about "scanning the fields" is just a kind of traversal of the AST representing the program. 你关于“扫描字段”的评论只是代表程序的AST的一种遍历。 For each interesting analysis result you produce, you want to make a change to the AST, perhaps somewhere else, but nonetheless in the AST. 对于您生成的每个有趣的分析结果,您希望对AST进行更改,可能在其他位置,但仍然在AST中。 And after all the chagnes are made, you want to regenerate text with comments (as originally entered, or as you have constructed in your new code). 在完成所有chagnes后,您需要使用注释(最初输入或在新代码中构建)重新生成文本。

There are several tools that do this specifically for Java. 有几种工具专门用于Java。

Jackpot provides a parser, builds ASTs, and lets you code Java procedures to do what you want with the trees. Jackpot提供了一个解析器,构建了AST,并允许您编写Java过程来对树进行所需的操作。 Upside: easy conceptually. 好处:简单概念。 Downside: you write a lot more Java code to climb around/hack at trees than you'd expect. 缺点:你写了很多Java代码来爬树/砍伐树木而不是你期望的。 Jackpot only works with Java. Jackpot仅适用于Java。

Stratego and TXL parse your code, build ASTs, and let you write "surce-to-source" transformations (using the syntax of the target language, eg, Java in this case) to express patterns and fixes. StrategoTXL解析您的代码,构建AST,并让您编写“surce-to-source”转换(使用目标语言的语法,例如本例中的Java)来表达模式和修复。 Additional good news: you can define any programming language you like, as the target language to be processed, and both of these have Java definitions. 其他好消息:您可以定义您喜欢的任何编程语言,作为要处理的目标语言,并且这两种语言都具有Java定义。 But they are weak on analysis: often you need symbol tables, and data flow analysis, to really make analyses and changes you need. 但他们在分析方面很薄弱:通常需要符号表和数据流分析才能真正进行所需的分析和更改。 And they insist that everything is a rewrite rule, whether that helps you or not; 而且他们坚持认为一切都是重写规则,无论是否有所帮助; this is a little like insisting you only need a hammer in toolbox; 这有点像坚持你只需要工具箱中的锤子; after all, everything can be treated like a nail, right? 毕竟,一切都可以像钉子一样对待,对吧?

Our DMS Software Reengineering Toolkit allows the definition of an abitrary target language (and has many predefined langauges including Java ), includes all the source-to-source transformation capabilities of Stratego, TXL, the procedural capability of Jackpot, and additionally provides symbol tables, control and data flow analysis information. 我们的DMS软件再造工具包允许定义一个abitrary目标语言(并有许多预定义语言, 包括Java ),包括Stratego,TXL的所有源到源转换功能,Jackpot的程序功能,并另外提供符号表,控制和数据流分析信息。 The compiler guys taught us these things were necessary to build strong compilers (= "analysis + optimizations + refinement") and it is true of code generation systems too, for exactly the same reasons. 编译人员告诉我们,这些东西对于构建强大的编译器(=“分析+优化+优化”)是必要的,并且由于完全相同的原因,它也适用于代码生成系统。 Using this approach you can generate code and optimize it to the extent you have the knowledge to do so. 使用此方法,您可以生成代码并在您具备相关知识的范围内对其进行优化。 One example, similar to your serialization ideas, is to generate fast XML readers and writers for specified XML DTDs; 类似于序列化思想的一个例子是为指定的XML DTD生成快速的XML读取器和编写器; we've done that with DMS for Java and COBOL. 我们已经使用DMS for Java和COBOL完成了这项工作。

DMS has been used to read/modify/write many kinds of source files. DMS已用于读取/修改/写入多种源文件。 A nice example that will make the ideas clear can be found in this technical paper, which shows how to modify code to insert instrumentation probes: Branch Coverage Made Easy . 可以在本技术论文中找到一个很好的例子,使这些想法变得清晰,该技术论文展示了如何修改代码以插入仪器探针: 分支覆盖范围变得容易 A simpler, but more complete example of defining an arbitrary lanauges and transformations to apply to it can be found at How to transform Algebra using the same ideas. 可以在如何使用相同的思想转换代数中找到一个更简单但更完整的定义应用于它的任意lanauges和变换的示例。

Have a look at Java Emitter Templates . 看看Java Emitter模板 They allow you to create java source files by using a mark up language. 它们允许您使用标记语言创建Java源文件。 It is similar to how you can use a scripting language to spit out HTML except you spit out compilable source code. 它类似于如何使用脚本语言来吐出HTML,除非您吐出可编译的源代码。 The syntax for JET is very similar to JSP and so isn't too tricky to pick up. JET的语法与JSP非常相似,因此不太难以接受。 However this may be an overkill for what you're trying to accomplish. 然而,对于你想要完成的事情,这可能是一种过度杀伤力。 Here are some resources if you decide to go down that path: 如果您决定沿着这条路走下去,这里有一些资源:

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

Modifying the same java source file with auto-generated code is maintenance nightmare. 使用自动生成的代码修改相同的java源文件是维护噩梦。 Consider generating a new class that extends you current class and adds the desired method. 考虑生成一个扩展当前类的新类,并添加所需的方法。 Use reflection to read from user-defined class and create velocity templates for the auto-generating classes. 使用反射从用户定义的类中读取并为自动生成类创建速度模板。 Then for each user-defined class generate its extending class. 然后为每个用户定义的类生成其扩展类。 Integrate the code generation phase in your build lifecycle. 在构建生命周期中集成代码生成阶段。

Or you may use 'bytecode enhancement' techniques to enhance the classes without having to modify the source code. 或者您可以使用“字节码增强”技术来增强类,而无需修改源代码。

Updates: 更新:

  1. mixing auto-generated code always pose a risk of someone modifying it in future to just to tweak a small behavior. 混合自动生成的代码总是会有人在将来修改它的风险,只是为了调整一个小的行为。 It's just the matter of next build, when this changes will be lost. 这只是下一次构建的问题,当这种变化将会丢失时。
  2. you will have to solely rely on the comments on top of auto-generated source to prevent developers from doing so. 您必须完全依赖自动生成源代码之上的注释来阻止开发人员这样做。
  3. version-controlling - Lets say you update the template of someMethod(), now all of your source file's version will be updated, even if the source updates is auto-generated. 版本控制 - 假设您更新了someMethod()的模板,现在您的所有源文件版本都将更新,即使源更新是自动生成的。 you will see redundant history. 你会看到多余的历史。

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

Iterating through the fields and defining someMethod is a pretty vague problem statement, so it's hard to give you a very useful answer, but Eclipse's refactoring support provides some excellent tools. 迭代字段并定义someMethod是一个非常模糊的问题陈述,因此很难给出一个非常有用的答案,但Eclipse的重构支持提供了一些很好的工具。 It'll give you constructors which initialize a selected set of the defined members, and it'll also define a toString method for you. 它将为您提供初始化所选定义成员集的构造函数,并且它还将为您定义toString方法。

I don't know what other someMethod()'s you'd want to consider, but there's a start for you. 我不知道其他someMethod()你想要考虑什么,但是有一个开始。

I'd be very wary of injecting generated code into files containing hand-written code. 我非常谨慎地将生成的代码注入包含手写代码的文件中。 Hand-written code should be checked into revision control, but generated code should not be; 应该将手写代码检入修订控制,但生成的代码不应该; the code generation should be done as part of the build process. 代码生成应该作为构建过程的一部分完成。 You'd have to structure your build process so that for each file you make a temporary copy, inject the generated source code into it, and compile the result, without touching the original source file that the developers work on. 您必须构建构建过程,以便为每个文件创建临时副本,将生成的源代码注入其中,然后编译结果,而不触及开发人员处理的原始源文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM