[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2110) Proxied object causes ClassCastException when method returns 'this' in a composite hierarchy

Diego Ballve (JIRA) noreply at atlassian.com
Fri Dec 14 13:34:56 EST 2007


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2110?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_29155 ] 

Diego Ballve commented on HHH-2110:
-----------------------------------

I got to a similar situation as Philip and at least in my case the problem is that CGLIB will collect ALL interfaces when loading by id + class, including interfaces only defined for some subclasses. To illustrate, I'll use Apples and Oranges, which are both Fruits:

public interface Fruit {
    String getId();
    void setId(String id);
}
public class FruitImpl implements Fruit {
    private String id;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}

public interface Apple extends Fruit {
}
public class AppleImpl extends FruitImpl implements Apple {
}

public interface Orange extends Fruit {
}
public class OrangeImpl extends FruitImpl implements Orange {
}

The mapping for that is:
	<class name="fi.dae.test.FruitImpl"
		proxy="fi.dae.test.Fruit">
		<id name="id" type="string">
			<generator class="assigned" />
		</id>
		<discriminator column="TYPE" type="string"/>
		
		<subclass discriminator-value="A"
			name="fi.dae.test.AppleImpl"
			proxy="fi.dae.test.Apple">
		</subclass>

		<subclass discriminator-value="O"
			name="fi.dae.test.OrangeImpl"
			proxy="fi.dae.test.Orange">
		</subclass>
	</class>

And the test:
                // create test content
                Apple apple = new AppleImpl();
                apple.setId("theApple");
                session.save(apple);

                // flush, restart transaction, get new session
                ...

                // check that theApple is Apple, not Orange, even if loaded as Fruit
                Object apple = session.load(FruitImpl.class, "theApple");
                assertTrue(apple instanceof Fruit);
                assertTrue(apple instanceof Apple);
                assertTrue(!(apple instanceof Orange));

Hibernate is mixing Apples and Oranges!

I don't know how feasible it is, but I believe the proxy constructing algorithm should peek into the subclasses definitions and into the value of the discriminator field, and based on that use only the proper interfaces for that given subclass.


> Proxied object causes ClassCastException when method returns 'this' in a composite hierarchy
> --------------------------------------------------------------------------------------------
>
>                 Key: HHH-2110
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2110
>             Project: Hibernate3
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 3.0.5
>         Environment: Hibernate 3, any database (test case uses HSQL, issue found using Oracle)
>            Reporter: Philip Nightingale
>         Attachments: HibernateClassCastExceptionTest.zip
>
>
> If a proxied object has a method that returns 'this' and the proxy type extends the same base class as the target object and the return type of the method is the target class type then a ClassCastException is thrown.
> The error can be tracked down to the method CGLibLazyInitializer::intercept(Object, Method, Object[], MethodProxy).
> In this method, if the object returned from the method call on the target object is the same as the target object, then instead of returning the object itself the proxy is returned. This is fine in most cases, but in the special case described, in which the proxy extends a base class that is also extended by the target class, then the CCE occurs.
> In the submitted test case I have a simple composite hierarchy with an abstract base type and two concrete subtypes. Either type can contain children, but only one can be the root of the hierarchy (and cannot itslef be a child). There is a many-to-one relationship defined from the sub-type that may be a child to the base class.
> The submitted test case is configured to use Hypersonic DB so hsqldb.jar is required on the classpath.
> Further details and code snippets from the original code that caused the exception are posted on the Hibernate user forum (topic "ClassCastException with CGLIB Lazy Initialization")

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list