views:

249

answers:

1

As a new Hibernate user, I have heard that a good pattern for adding some helper methods to generated classes is to add them in a subclass. For example:

// generated via  Hibernate mapping file
public class GeneratedClass {
  long id;
  String someValue;

  // etc, etc.
}

// my own class with pretty printing method
public class MyGeneratedClass extends GeneratedClass {
  public String prettyPrint() {
     return "an object: " + id + "," + someValue;
  }
}

What I would like to be able to do is the following: have Hibernate return objects of type MyGeneratedClass instead of GeneratedClass so that I can work with the subclass directly. Can the mapping file be defined in this way (i.e. without the generation overwriting any custom code)?

For any possible solution, if GeneratedClass is part of a class hierarchy (i.e. GeneratedClassTypeA, GeneratedClassTypeB both which extend GeneratedClass), would this pattern still work?

I suppose an alternative would be to create a static factory method to create MyGeneratedClass from GeneratedClass, but this seems inefficient for a large number of objects.

Thanks in advance!

EDIT

After trying out the union-class strategy, I realized it did not work in my situation because of the existing class hierarchy and data. Also, I could not control the generation from overwriting my subclass (a desirable feature in hbm2java maybe?). Finally, I did consider embedding code inside mapping file, but overriding things like getters and setters looked pretty tedious.

I reviewed the approach and decided to go with annotating the domain objects and avoid using hbm2java entirely. It's not entirely ideal (the mapping seemed easier to deal with), but from what I have gathered from various sources, it might be the most appropriate way to deal with my particular situation because it gives me the freedom to customize the code with type checking and deal with only the class file.

I'd welcome any other thoughts or comments on my solution.

EDIT 2

The solution proposed below, using

<meta attribute="generated-class">CountryBase</meta>

is a good solution to the original problem which was described originally. However, what I discovered was that having object hierarchies and using superclass methods does not work as well with this solution, in which case annotations seems to be a better bet.

+1  A: 

What I would like to be able to do is the following: have Hibernate return objects of type MyGeneratedClass instead of GeneratedClass so that I can work with the subclass directly. Can the mapping file be defined in this way?

Yes, you just need to specify your subclass in the mapping: <class name="Subclass" table="table">. Then you use Subclass.class to query the entities.

For any possible solution, if GeneratedClass is part of a class hierarchy (i.e. GeneratedClassTypeA, GeneratedClassTypeB both which extend GeneratedClass), would this pattern still work?

Yes. As long as the properties defined in the mapping exist in the class (be it because of inheritence), it should work.

I suppose an alternative would be to create a static factory method to create MyGeneratedClass from GeneratedClass, but this seems inefficient for a large number of objects.

Indeed.

EDIT

I didn't understood from your question that you generated the class out of the mapping. I thought it was generated from some other model that would spit the mapping and the class. Your comment clarified this. I would then try an approach using hibernate inheritance:

<class name="GeneratedClass" abstract="true">
    <id name="id" type="long" column="XXX">
        <generator class="sequence"/>
    </id>
    <property name="zzzz" column="ZZZZ"/>
    ...
    <union-subclass name="SubClass" table="TABLE">
    </union-subclass>
</class>

I didn't tested the snippet above, but I'm fairly convinced that your scenario can be mapped one way or the other. The abstract=true is maybe superfluous, but it shows the fact that the parent superclass should not be instanciated. The subclass has no additional property so the subclass tag is empty.

EDIT 2

Did you also try with <meta attribute="generated-class">CountryBase</meta>? Never used it but it seems to fit this purpose. See "Using a Base Class" in Hibernate Class Generation with hbm2java

ewernli
Just to clarify in the context of the example above, I would put <class name="MyGeneratedClass><!-- mapping for id, value properties --></class>and there would be no mapping for GeneratedClass itself?But if I generate the Java classes from this mapping, won't that overwrite any custom code I have written?
slau
Thanks for the snippet. What I found was that when I inserted it into my existing domain object hierarchy, the union-subclass changed the DB schema since I was originally using join-subclass (sorry I didn't point that out earlier) - so that's kind of a dealbreaker for me. The approach works for any new classes I am adding in that are not part of the hierarchy, but it still has the tendency to overwrite the class when hbm2java is used. I searched for hbm2java control parameters without success; I guess I am thinking of something like EMF's ability to annotate code to prevent overwriting.
slau
Also, can't you use Hibernate 3 and annotations to keep the mapping and the code together? I find in much convenient that configuraiton files. Do you also generate the database schema out of the mapping?
ewernli
And a last remark: form my personal experience, regeneration of the base classes happens only a few time at the early stage of the project. After some times, the model gets stables and process of regenerating the classes (running the tool, making sure everything is ok, etc.) tend to be heavier than making the changes in both places. You anyway need to test thoroughly such changes (to make surce the types are correct, etc.), so the safety provided by an automated generation is from my POV not high in *this* case.
ewernli

related questions