views:

2715

answers:

6

With generated Java source code, like

  • code generated with Hibernate tools
  • code generated with JAXB schema binding (xjc)
  • code generated with WDSL2Java (cxf)

all generated classes are "value object" types, without business logic. And if I add methods to the generated source code, I will loose these methods if I repeat the source code generation.

Do these Java code generation tools offer ways to "extend" the generated code?

For example,

  • to override the ToString method (for logging)
  • to implement the visitor pattern (for data analysis / validation)
+2  A: 

It is not a good idea to edit generated code files, either by editing the files them selves or by subclassing. Whatever you do, be sure to leave the signature created by the tool intact, so that it will be possible to understand in the future that the file was auto-generated.

I recommend that you research the command options of the tools to see if they allow you some flexibility. Some tools can generate abstract classes or interfaces instead of concrete classes. If this is not possible, create a domain object that includes the autogenerated object as a member variable.

kgiannakakis
What would be the disadvantage of subclassing? It seems to be a working solution for Hibernate generated classes, for example.
mjustin
The only disadvantage is that your classes may break if you re-generate hibernate classes. I guess this isn't big deal, however I personally prefer composition and use instances of the hibernate classes as member variables. The most important thing is to make clear evident which classes are auto-generated and which not.
kgiannakakis
+6  A: 

As for Hibernate you may tweak the template files used in code generation to change their behaviour. If you want to tweak the HIbernate Tools you can edit, for example: dao/daohome.ftl

You may even add fields to the "toString()" output editing the .hbm.xml files

...
<property name="note" type="string">
    <meta attribute="use-in-tostring">true</meta>
    <column name="note" />
</property>
...

Both for logging and validation you may consider using AOP with AspectJ (I don't recommend messing with the generated code, since you might want to build that from scratch many times over).

Manrico Corazzi
+1 for the AOP citation.
duffymo
+2  A: 

First I would reiterate that modification of generated code has many problems associated with it and that, where possible it should be avoided. That said sometimes this is impractical to avoid or more effort than just dealing with the changes when the code is regenerated.

Sadly java doesn't support the concept of partial classes that c# has. These are precisely to solve this sort of problem.

You should see if your code generation tools support some form of meaningful comments which delimit regions added by yourself in the class (this is unlikely and won't help if you are modifying the code rather than adding to it)

You best option if you really wish to do this is to generate the files initially but check them into a version control repository immediately. Then make your changes, check that in.

Next time you rerun the tools and let them overwrite the existing files you can diff against your source controlled ones and merge the changes back in (most trivial changes like addition of new columns/tables will be little effort.

This will not help you as much if the code generator suddenly generates radically different code (say a new version) but in those cases any code you added which wasn't simply additional convenience methods relying on data/methods already exposed publicly) will have problems no matter how it is mixed into the class. The version control system does still help however since it also records the original changes so you can see what you had added previously and what, one would assume, you need to recreate in the new style.

ShuggyCoUk
+5  A: 

For JAXB, see Adding Behaviours.

Basically, you configure JAXB to return a custom instance of the object you'd normally expect. In the below example you create a new object PersonEx which extends the JAXB object Person. This mechanism works well in that you're deriving from the generated classes, and not altering the JAXB classes or schemas at all.

package org.acme.foo.impl;

class PersonEx extends Person {
  @Override
  public void setName(String name) {
    if(name.length()<3) throw new IllegalArgumentException();
    super.setName(name);
  }
}

@XmlRegistry
class ObjectFactoryEx extends ObjectFactory {
  @Override
  Person createPerson() {
    return new PersonEx();
  }
}

Note that the @Override directive is important in case your JAXB object changes - it'll prevent your customisation becoming orphaned.

Brian Agnew
This looks great, I discovered JAXB and CXF a couple of days ago and both seems to be very powerful and configurable
mjustin
Good. I've used this in the past, and with multiple teams, you can use the same schemas and implement different behaviours (whether that's a good thing or not is debatable!)
Brian Agnew
In addition to the above (which is good advice), the jaxb code generator (xjc) does have a plugin mechanism to allow the code generator to generate extra "stuff". There are "toString" plugins, hashCode plugins, etc... to add that stuff. You could write your own as well. The above stuff is definitely better for business logic stuff, but for simple things you want applied to all classes, the plugins work OK.
Daniel Kulp
+1  A: 

The AOP citation is a good one. I'll add Spring, which has very nice AOP features built in.

duffymo
+3  A: 

The way I have used Hibernate is to generate base classes that I then extend. I add all my business logic (if any) to these subclasses. I quite often also end up changing the FreeMarker templates used by Hibernate to further customize the generated classes.

willcodejavaforfood
This is actually a rather good way. Hibernate can instanciate the subclasses, and the generated classes are never used directly. It's easy to regenerate the superclasses and if there are changes in the model that affects the business methods, you will get compilation errors in the subclass that is easy to fix.
KarlP
This is handy but not very clear from design's point of view. Your subclass acts both in Data Access and Business layer - this is against separation of concerns principle.
kgiannakakis