Hello everybody.
I am not really asking for help, since I already have 'solved' the problem.
I am just curious if this problem arose due to:
A. Crummy architectural decisions on my part (now there's an invitation if there ever was one)
B. Limitations in the Hibernate property reflection methods
C. Other..
Now, to the 'problem':
(I am using Hibernate 2.1, Oracle9 and J2SE 1.4.2 by the way)
I am using a custom enum class with singleton values, mapping to strings in the database.
The class hierarchy makes heavy use of inheritance and polymorphism - it's a metamodel framework similar to MOF/UML.
I have
Code:
public String getX()
protected setX(String)
public setX(MyEnum)
in a superclass (A).
The
setX(String) is necessary for proper Hibernate behaviour, but in order to keep things clean, I have given it protected access and provided a
setX(MyEnum)instead in order to control enum data values more easily.
The violating subclass has overridden the
public setX(MyEnum) in order to make a few extra assertations appropriate for the subclass.
ReflectionOptimizer is turned off for both.
So, basically the code is:
Code:
class A {
private MyEnum x;
public String getX() { return x.toString(); }
protected void setX(String s) { x = MyEnum.fromString(s); }
public void setX(MyEnum e) { x = e; }
}
class B extends A {
public void setX(MyEnum e) {
//make assertations...
super.setX(e);
}
}
I have not attached the mapping document, because i really do not think that the problem exists there. However, property X is mapped as a String in superclass A. Nothing fancy really.
The problem is, Hibernate gets the string value from the database, but tries to use the
B.setX(MyEnum) instead of
A.setX(String), resulting in a PropertyAccessException. Instances of A do not show this problem.
The solution? Very simple, just add a
Code:
protected void setX(String s) {super.setX(s);}
forwarding method to class B.
I must admit, I have not looked into the Hibernate source yet (beyond debugging this), but I am curious - does the property reflection algorithm stop when a setter method with suitable name is found or does it really traverse the entire superclass hierarchy for more suitable method signatures? It must be the former, right? Otherwise maybe my solution was misplaced, fixing a problem that originates elsewhere..
I do not want to use the PersistentEnum class, things are clearer with string enums(and allows for smoother use of the data from other systems) and I think using UserType is too much for a simple enum.
True, this is probably not a common problem, and is really easy to fix, but I like to keep code nice and clean and adding a forwarding method feels like a hack. A flag for turning 'exact' getter/setter signatures on in Hibernate would be nice... (I know, I know - 'Do it yourself, you whining bastard!')
Anyway, my question is: Is this 'limitation' a concious design choice to speed up reflection property mapping, is this example rare or architectually quirky enough to have been overlooked or worse - should my example have worked the first time?
//emser
PS. Apart from this little thing, the OO-properties in Hibernate are really, really good. The models i have tried sofar make insane use of object oriented concepts and Hibernate just swallows them and generates slim databases for all. I have started to use it to generate good O/R mappings, even if I do not use Hibernate as the persisting mechanism in the end.