Automatically generating Java source code

22,961

Solution 1

Modifying the same java source file with auto-generated code is maintenance nightmare. 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. you will see redundant history.

Solution 2

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. Your remark about "scanning the fields" is just a kind of traversal of the AST representing the program. For each interesting analysis result you produce, you want to make a change to the AST, perhaps somewhere else, but nonetheless in the 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).

There are several tools that do this specifically for Java.

Jackpot provides a parser, builds ASTs, and lets you code Java procedures to do what you want with the trees. Upside: easy conceptually. Downside: you write a lot more Java code to climb around/hack at trees than you'd expect. Jackpot only works with Java.

Stratego and TXL parse your code, build ASTs, and let you write "surce-to-source" transformations (using the syntax of the target language, e.g., Java in this case) to express patterns and fixes. 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. 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. 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; we've done that with DMS for Java and COBOL.

DMS has been used to read/modify/write many kinds of source files. 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.

Solution 3

Have a look at Java Emitter Templates. They allow you to create java source files by using a mark up language. It is similar to how you can use a scripting language to spit out HTML except you spit out compilable source code. The syntax for JET is very similar to JSP and so isn't too tricky to pick up. 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:

Solution 4

You can use cglib to generate code at runtime.

Solution 5

Antlr is really a great tool that can be used very easily for transforming Java source code to Java source code.

Share:
22,961
Tony the Pony
Author by

Tony the Pony

Updated on May 05, 2020

Comments

  • Tony the Pony
    Tony the Pony about 4 years

    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.

    In essence, I'm looking to execute the following steps:

    1. Read and parse SomeClass.java
    2. Iterate through all fields defined in the source code
    3. Add source code method someMethod()
    4. Save SomeClass.java (Ideally, preserving the formatting of the existing code)

    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

  • Tony the Pony
    Tony the Pony about 13 years
    Thanks. My thinking is that injecting auto-generated code is clearer and more maintainable than the "invisible magic" of bytecode enhancement, but I'd be curious about specifics regarding maintainability of my proposed approach
  • Tony the Pony
    Tony the Pony about 13 years
    I've posed it as a new question: stackoverflow.com/questions/5746099/…
  • Tony the Pony
    Tony the Pony about 13 years
    Thanks! I'm looking to generate persistence code for model classes, which would only change whenever the class code itself has been changed. (Unfortunately, there are no partial classes in Java)
  • Wyzard
    Wyzard about 13 years
    @Jen, would it make sense to do that using reflection, possibly guided by annotations on the model class, rather than actually modifying each class that needs to be persisted?
  • Tony the Pony
    Tony the Pony about 13 years
    Yes, that is a valid approach also, but I'm looking for a) higher performance and b) greater code clarity (My thinking is that it is easier to tell what is going on by reading the generated code than trying to work out the different conventions/annotations)