13

In response to my question regarding Java source code generation, I received this answer warning me about potential maintenance problems:

  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.

His proposed alternative is enhancing classes at runtime using bytecode generation.

My thinking was that injecting generated code into existing source code files would enhance maintainability, because it makes it obvious what is going on instead of performing some operations behind the scenes.

Should I:

  1. create a tool to add generated code to existing source code; or

  2. augment the classes using bytecode generation at runtime?

What has been your experience with either of these approaches?

Tony the Pony
  • 440
  • 1
  • 3
  • 10
  • 1
    "you will have to solely rely on the comments on top of auto-generated source to prevent developers from doing so" Nope. You can also give the generated file a file name like "machine_generated_file_1.xxx". While not everyone reads comments, most will know the file name at least. – Thomas Eding Jun 24 '14 at 23:03
  • 1
    @Thomas: that doesn't work too well in Java, where the source file name has to match the class name and the entire class definition has to reside in that file. – kevin cline Oct 20 '14 at 06:39

6 Answers6

15

I have done a middle sized Java project (ca. 300 classes) with multiple Maven modules with my domain classes auto generated (ca. 100 classes) from a DSL done with the superb Eclipse Xtext project and I would do it again :)

Here I will give hints how I (till today) successfully come around the cumber stones mentioned:

Since my project was build with maven I used the maven way to handle auto generated code, that means even my xtext dsl and generator project is handled by maven and at every full build I create all generated code new (as it should be). See: building xtext projects with maven tycho. So in my project I only have to do a "maven package".

I divided my generated code and my hand typed via inheritance (i dislike the c# way to span a class in multiple files):

/* Generated code, will not be in revision control */
abstract class AbstractFoo {
    //getters and setters
    //collection accessors
    //helper methods like toString equals hashCode
}

/* Generated one time, will be in revision control */
class Foo extends AbstractFoo{
    //business logic if needed
}

With an Xtext generator project it is possible to define files that should only be created one time, so my concrete classes i have created only one time and kept then in my Git repo. The generated concrete class is nothing more then a 2 liner so you can use the class even if you add no methods to it.

For the two templates (abstract and concrete) I have created two test class templates one for the abstract class and one for the concrete, but the concrete test class is again only just generated one time and a two liner.

In my maven module where the generated code is located i have used this layout (almost the maven conventions):

myproject/src/main/java -> concrete generated classes, one time
myproject/src/test/java -> generated tests, one time
myproject/target/generated-sources/mydsl -> abstract generated classes, always
myproject/target/generated-sources/mydsltests -> auto generated tests, always

So when i change the template only the template in the Xtext generator project will change in my revision control, since I do not include the (always) generated sources.

So I would suggest you to give Eclipse Xtext a try, when you start with the example projects you will have something prototypish running in less then one hour.

moritz
  • 266
  • 1
  • 2
  • 3
    +1 great, particularly the not checking your generated sources into version control. That's the ONLY way to do it, of course. – Dan Rosenstark Apr 23 '11 at 06:44
7

I would not like this approach one bit. Too much mystery for my taste.

I'd prefer aspects or decorators, because you have to actually write them instead of generating them AND you make clear what you're doing when you weave them in.

duffymo
  • 3,032
  • 16
  • 23
  • 3
    Also generated code can be a maintenance nightmare as you then have to fix the code that generates the faulty code, not the faulty code itself. It always sounds good, but beware. – cjstehno Apr 21 '11 at 15:24
5

From what I've seen, source code generation works best if:

  1. You don't have any reason to modify the class's code once it's been generated, or
  2. You won't have any reason to re-generate a class's code once you've modified it (scaffolding approach), or
  3. You're working in a language like C#, which allows you to make classes span multiple files. (You can have one file with auto-generated code, and another with your contributions), or

Based on your question, I'm guessing none of these is probably true. While I haven't personally done bytecode generation, I've noticed that some well-used tools like GWT have chosen that approach, so it's probably preferable.

However, I'd ask a colleague to listen to what you're ultimately trying to accomplish and see if there's not a better way using more standard Java practices.

StriplingWarrior
  • 2,407
  • 1
  • 16
  • 21
  • The way you make 1. happen is to *always* generate the generated files. That way you have no need to touch them. – Ira Baxter Apr 22 '11 at 01:56
  • I would disagree with 1, since that is the entire idea behind scaffolding, a pretty widely accepted practice. – Morgan Herlocker Jun 14 '11 at 17:44
  • @Ira Baxter: Precisely. If you can always use generated files, that's fine. If you need to be able to override behavior in certain cases, the generation framework must support that so you don't have to manually modify the code. – StriplingWarrior Jun 14 '11 at 18:55
  • 1
    @ironcode: I was originally thinking of code generation where the code needs to be re-generated on a regular basis (a la "update model from database schema"), which is what the OP sounds like he's doing. But broadly speaking, you're right: I added a new #2 to include the scaffolding idea. – StriplingWarrior Jun 14 '11 at 19:00
4

You can have your build process generate the code, jar it up, and include it on the classpath of your dependent project. This will prevent the issue with rogue devs changing the generated source, you don't need to version the generated jar just the meta data it was built from.

This was the approach I've used in the past with tools like XMLBeans and it worked pretty well.

nsfyn55
  • 393
  • 2
  • 7
  • How do the rogue devs debug the generated code, or is it assumed to be bug-free? – quant_dev Apr 23 '11 at 20:21
  • Attach the source, but generated code should be bug free. If you find a problem with the generated source then you need fix your generator. – nsfyn55 Apr 25 '11 at 18:57
  • "If you find a problem with the generated source" - you need to be able to debug it, then. So you need to attach the generated source. I'm not saying that you will fix it my modifying the generated source (that's stupid), but you need to see the generated source. – quant_dev Apr 26 '11 at 06:40
  • isn't that what I said - attach the source. – nsfyn55 Apr 27 '11 at 20:28
2

The Eclipse Modeling Framework does really superb code generation, but is complicated to get to grips with. It is apparently able to allow user code additions in the model code without reverting those changes each time the model is regenerated. Also, the Mattise UI editor in Netbeans does all the generation for the user interface, and keeps it up to date.

1

Actually in managed c++ forms you have both automatic and manual codes mixed together in the .h file. Automatic code is updated every time you open form in designer mode, modify something and save. Works just as well as having generated code in a separate file.

AareP
  • 369
  • 1
  • 7