Hibernate uses proxies to enable lazy loading of collections and even single-ended associations. According to Hibernate's (3.6.5) reference documentaion (Section 21.1.3, Single-ended association proxies), such a proxy can't be constructed by Hibernate if it contains "any final methods".
My question is, does this restriction apply to getters/setters of persistent fields only or really to any method in an entity class? So, does a method like this one:
public final String toString() {
return this.getClass().getSimpleName() + id;
}
really prevent the creation of a (CGLIB or Javassist) proxy for this entity? Does it matter if field-based or property access is used? Since CGLIB was replaced by Javassist, does this provide any more features in this direction?
I like to use inheritance in my entity hierarchy and hence the requirement to define some final methods, for example, in the base class to prevent subclasses from overriding those methods.
thanks in advance!
By the help of the Hibernate mailing list (thanks Emmanuel Bernardt!) I'm able to answer my own question, the summary is:
Final methods do not prevent Hibernate from creating a proxy in general but unless those methods don't use any state of the entity this is highly inadvisable.
Some background information: Hibernate doesn't use bytecode enhancement neither with cglib nor with Javassist so, in order for a proxy to initialize its target entity lazily it has to intercept any method which may use the state of that target entity. Now it's perfectly ok to have a final method like this
public final doSomething(String a, Integer b ) {
// do complicated stuff using only a and b (no instance members accessed!)
}
but as soon as this method uses any persistent field directly or through another instance method this would bypass the proxy and thus lead to unexpected behaviour.
As a sidenote this is the same reason why you should not access fields of other instances directly, for example in an entities equals
method:
// XXX bad code!
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Profile)) return false;
Profile profile = (Profile) o;
// XXX this bypasses a possible proxy, use profile.getName() instead!
return (name == null ? profile.name == null : name.equals(profile.name));
}
I'm pretty sure that, as the reference says, it applies to any method. Indeed, a proxy, in my understanding, is nothing more than a subclass of the entity which has no state except for the ID of the entity initially, and which delegates every method call to an actual instance of the entity class once initialized. It thus has to override all of the methods in order to
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With