This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 245107

Summary: Generated Entity Bean equals() method inconsistent with Lazy Loading relationships and JSF selectItems
Product: javaee Reporter: richyclarke
Component: PersistenceAssignee: Sergey Petrov <sj-nb>
Status: RESOLVED WONTFIX    
Severity: normal CC: marfous
Priority: P3    
Version: 8.0   
Hardware: PC   
OS: Windows 8   
Issue Type: DEFECT Exception Reporter:

Description richyclarke 2014-06-17 13:51:40 UTC
In JSF, where a selectOneMenu component is used, and a converter is specified like so;

<h:selectOneMenu value="#managedBean.realm" converter="#realmConverter">
    <f:selectItems value="#managedBean.possibleRealms"/>
</h:selectOneMenu>

...the equals() method of the class is called to compare the objects.
 
The auto generated equals() method, generated when creating entity beans from database tables, doesn't accommodate lazy loaded entities, as it doesn't use the getter methods when accessing 'other' object properties.

The generated code typically compares entity id's like this;

if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id)))
...

When using lazily loaded relationships, the entity is being compared with it's proxy (e.g. object with class "Realm" against an object with class "Realm_$$_javassist_34535"). 

The proxy is invoked by the getter method, so if you access the id directly, it is null, however if you access getId(), you get the valid value of the ID.

Consequently the equals method (and probably hashcode() method too)should call the getter method instead of accessing the field (e.g. do 'this.getId().equals(other.getId())' instead of 'this.id.equals(other.id)').

This way lazy initializer will load properties you are using in comparison.
Comment 1 Martin Fousek 2014-06-20 06:01:56 UTC
Thanks for reporting.
Comment 2 Martin Fousek 2014-07-10 09:18:13 UTC
Reassigning since the issue is about "equals", "hashCode" methods generated by the persistence support.
Comment 3 Sergey Petrov 2014-07-21 14:55:03 UTC
Is it applicable to entities with property access only? In case of field access there may be no getters, also by default entities are generated with getters but also with field access type, I'm not sure equal should use getters in this case.
Comment 4 Sergey Petrov 2014-07-21 15:03:45 UTC
also first part of equal contain
        if (!(object instanceof Customer)) {
            return false;
        }

how it will survive compare '"Realm" against an object with class "Realm_$$_javassist_34535"'?
Comment 5 richyclarke 2014-07-22 16:54:25 UTC
Sergey,

You are right, by default entity classes are generated with field access, however getters are always generated.

By default the fetch type of an object's properties, including ManyToOne related objects, is eager, so this is normally not an issue, since proxies are not invoked. However if a generated class is the target of a ManyToOne mapping and the fetch type of that mapping is set lazy (using 'fetch=FetchType.LAZY'), then the class will use a proxy for the related object. In this specific use case, the equals method has to use the getter method otherwise the proxy will not be invoked and the object will always return null. 

If Netbeans always generates a getter method, then I don't see a problem using the getters in the equals method.  

On your second point re 'instanceof', the proxy is a subclass of the lazily loaded class, so in the example 'Realm_$$_javassist_34535' would be a subclass of 'Realm'. The proxy object will therefore pass the instanceof test because instanceof returns true for subclassed objects.

Rich
Comment 6 Martin Balin 2016-07-07 08:56:40 UTC
This old bug may not be relevant anymore. If you can still reproduce it in 8.2 development builds please reopen this issue.

Thanks for your cooperation,
NetBeans IDE 8.2 Release Boss