As far as I know, hibernate tries to build proxies for all objects since Hibernate 3. You can add lazy="false" to the class tag, but these will result in heavy database traffic...
I changed some code in the latest CVS snapshot of ACEGI, and it works great:
Class net.sf.acegisecurity.acl.basic.NamedEntityObjectId entity:
Code:
package net.sf.acegisecurity.acl.basic;
import org.springframework.util.Assert;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Simple implementation of {@link AclObjectIdentity}.
*
* <P>
* Uses <code>String</code>s to store the identity of the domain object
* instance. Also offers a constructor that uses reflection to build the
* identity information.
* </p>
*
* @author Ben Alex
* @version $Id: NamedEntityObjectIdentity.java,v 1.4 2005/05/09 01:18:29 benalex Exp $
*/
public class NamedEntityObjectIdentity implements AclObjectIdentity
{
//Added by PSM (see http://cglib.sourceforge.net/apidocs/net/sf/cglib/core/DefaultNamingPolicy.html)
private static final String CGLIB_NAMING_POLICY = "$$EnhancerByCGLIB$$";
//~ Instance fields ========================================================
private String classname;
private String id;
//~ Constructors ===========================================================
public NamedEntityObjectIdentity(String classname, String id) {
if ((classname == null) || "".equals(classname)) {
throw new IllegalArgumentException("classname required");
}
if ((id == null) || "".equals(id)) {
throw new IllegalArgumentException("id required");
}
//Changed by PSM
this.classname = getClassNameWithOutCGLib(classname);
this.id = id;
}
/**
* Creates the <code>NamedEntityObjectIdentity</code> based on the passed
* object instance. The passed object must provide a <code>getId()</code>
* method, otherwise an exception will be thrown.
*
* @param object the domain object instance to create an identity for
*
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public NamedEntityObjectIdentity(Object object)
throws IllegalAccessException, InvocationTargetException {
Assert.notNull(object, "object cannot be null");
//Changed by PSM
this.classname = getClassNameWithOutCGLib(object.getClass().getName());
Class clazz = object.getClass();
try {
Method method = clazz.getMethod("getId", new Class[] {});
Object result = method.invoke(object, new Object[] {});
this.id = result.toString();
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException("Object of class '" + clazz
+ "' does not provide the required getId() method: " + object);
}
}
protected NamedEntityObjectIdentity() {
throw new IllegalArgumentException("Cannot use default constructor");
}
//~ Methods ================================================================
/**
* Indicates the classname portion of the object identity.
*
* @return the classname (never <code>null</code>)
*/
public String getClassname() {
return classname;
}
/**
* Indicates the instance identity portion of the object identity.
*
* @return the instance identity (never <code>null</code>)
*/
public String getId() {
return id;
}
/**
* Important so caching operates properly.
*
* <P>
* Considers an object of the same class equal if it has the same
* <code>classname</code> and <code>id</code> properties.
* </p>
*
* @param arg0 object to compare
*
* @return <code>true</code> if the presented object matches this object
*/
public boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof NamedEntityObjectIdentity)) {
return false;
}
NamedEntityObjectIdentity other = (NamedEntityObjectIdentity) arg0;
if (this.getId().equals(other.getId())
&& this.getClassname().equals(other.getClassname())) {
return true;
}
return false;
}
/**
* Important so caching operates properly.
*
* @return the hash of the classname and id
*/
public int hashCode() {
StringBuffer sb = new StringBuffer();
sb.append(this.classname).append(this.id);
return sb.toString().hashCode();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(this.getClass().getName()).append("[");
sb.append("Classname: ").append(this.classname);
sb.append("; Identity: ").append(this.id).append("]");
return sb.toString();
}
/**
* Added by PSM
* Returns the classname without the CGLIB name extension
* @param name The className to be cleared
* @return The real className
*/
private String getClassNameWithOutCGLib(String name)
{
String realClassName = name;
if(name.indexOf(CGLIB_NAMING_POLICY)!=-1)
{
int endIndex = name.indexOf(CGLIB_NAMING_POLICY);
realClassName = name.substring(0,endIndex);
}
return realClassName;
}
}
Class net.sf.acegisecurity.acl.basic.NamedEntityObjectId entityTests
And a new test method:
Code:
public void testCleanEnhancedClasses()
{
NamedEntityObjectIdentity name = new NamedEntityObjectIdentity("net.sf.cglib.Foo$$EnhancerByCGLIB$$38272841","id");
assertEquals("net.sf.cglib.Foo", name.getClassname());
assertEquals("id", name.getId());
}