Issue Details (XML | Word | Printable)

Key: HHH-3718
Type: Bug Bug
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Paul Lorenz
Votes: 6
Watchers: 6
Operations

If you were logged in you would be able to see more operations.
Hibernate Core

call to id getter initializes proxy when using AccessType( "field" )

Created: 16/Jan/09 08:40 AM   Updated: 12/Jul/09 10:02 PM
Component/s: core
Affects Version/s: 3.3.1
Fix Version/s: None

Time Tracking:
Not Specified

File Attachments: 1. Text File ids.patch (3 kB)
2. Text File ids.patch (3 kB)

Environment:
hibernate 3.3.1, hibernate annotations 3.4.0, running on windows, linux and solaris, using sybase 15

Bug Testcase Reminder (view):
REMINDER: Bug reports should generally be accompanied by a test case
Participants: Paul Benedict and Paul Lorenz


 Description  « Hide

Calling getter for id when using AccessType( "field" ) causes proxy initialization.

In org.hibernate.proxy.proxy.pojo.BasicLazyInitializer there is the code

else if ( isUninitialized() && method.equals(getIdentifierMethod) ) { return getIdentifier(); }

However, when using field access, the getIdentifierMethod will be null. I fixed this for us by changing DirectPropertyAccessor by adding a Method attribute to the DirectGetter inner class, and looking up the appropriate getter in the constructor. As far as I can tell, getMethod is only used in two places. In the above case, to the get the identity getter and in PojoComponentTupilizer.isMethodOf. This doesn't seem to break anything. I don't know if this is a clean solution, seems a little hacky to me, however, it would be great if the issue could be fixed somehow.

public static final class DirectGetter implements Getter {
private final transient Field field;
private final Class clazz;
private final String name;
private Method method;
DirectGetter(Field field, Class clazz, String name) {
this.field = field;
this.clazz = clazz;
this.name = name;
try
{
BeanInfo beanInfo = Introspector.getBeanInfo( clazz );
PropertyDescriptor[] pdArray = beanInfo.getPropertyDescriptors();
if ( pdArray != null )
{
for (PropertyDescriptor pd : pdArray )
{
if ( pd.getName().equals( name ) )

{ this.method = pd.getReadMethod(); }

}
}
}
catch ( Exception e )

{ // ignore }

}
public Object get(Object target) throws HibernateException {
try { return field.get(target); }
catch (Exception e) { throw new PropertyAccessException(e, "could not get a field value by reflection", false, clazz, name); }
}

public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) { return get( target ); }

public Method getMethod() { return method; }
public String getMethodName() { return method == null ? null : method.getName(); }
public Class getReturnType() { return field.getType(); }

Object readResolve() { return new DirectGetter( getField(clazz, name), clazz, name ); }

public String toString() { return "DirectGetter(" + clazz.getName() + '.' + name + ')'; }
}



Paul Lorenz added a comment - 02/Jun/09 02:18 PM

Patch to solve issues with @AccessType( "field" ) and id getter invocation causing proxy initialization.


Paul Lorenz added a comment - 02/Jun/09 02:22 PM

I've added a patch to solve this problem slightly different, using a lazy lookup of the method.

We're also having a problem where the method being invoked is different from identified get method.

We have a common interface for entities which includes a method

Serializable getId ()

in a subclass, we have

Long getId ()

When the proxy is invoked, it invokes the Serializable getId () method, however the getIdentifierMethod in BasicLazyInitializer is the Long getId() method. Since they don't match, it initializes the proxy.

I replaced this with a heuristic based on method name and number of arguments, since this should be more accurate.


Paul Lorenz added a comment - 02/Jun/09 02:38 PM

Fixed patch. Original patch was reversed.


Paul Benedict added a comment - 12/Jul/09 10:02 PM

Sounds like an important bug to fix. I learned about it here:
http://blog.xebia.com/2009/06/13/jpa-implementation-patterns-field-access-vs-property-access/