[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-3230?page=c...
]
Diego del Río commented on HHH-3230:
------------------------------------
I made a TestCase, based on the class
{{org.hibernate.junit.functional.FunctionalTestCase}} belonging to the package
hibernate-testing, that reproduces the exception
{{org.hibernate.TransientObjectException}} thrown in the method
{{Session.getEntityName(String)}}. The test case, mapping files and entity classes are
attached in [^NarrowingProxyTestCase.zip]
{noformat}
package org.headlesspigs.test;
import org.headlesspigs.domainmodel.Invoice;
import org.headlesspigs.domainmodel.WorkingPerson;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.TransientObjectException;
import org.hibernate.junit.functional.FunctionalTestCase;
public class ProxyNarrowingTest extends FunctionalTestCase {
public ProxyNarrowingTest(String string) {
super(string);
}
public String[] getMappings() {
return new String[] { "Person.hbm.xml", "Invoice.hbm.xml" };
}
public String getBaseForMappings() {
return "org/headlesspigs/domainmodel/";
}
public boolean createSchema() {
return true;
}
public void testNarrowingProxy() throws Exception {
Session s = null;
Transaction tx = null;
WorkingPerson p1 = null;
WorkingPerson p2 = null;
Invoice inv = null;
try {
s = this.openSession();
tx = s.beginTransaction();
p1 = new WorkingPerson("Adrian");
p2 = new WorkingPerson("Batista", p1);
inv = new Invoice("A-462", p1, p2);
s.save(inv);
tx.commit();
} catch (Exception e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
if (s != null) {
s.close();
}
}
try {
s = this.openSession();
tx = s.beginTransaction();
inv = (Invoice) s.load(Invoice.class, inv.getId());
assertEquals("A-462", inv.getNumber());
// The following line causes the proxy to the emitter Person to be
// initialized. During this initialization, a proxy to
// the referee person is found but its type is Person and not
// WorkingPerson as needed, so Hibernate creates another proxy to
// the referee, this time of type WorkingPerson, replacing the old
// one.
assertEquals("Batista", inv.getEmitter().getName());
try {
s.getEntityName(inv.getReceiver());
fail("It should have thrown TransientObjectException");
} catch (TransientObjectException e) {
e.printStackTrace(System.err);
}
tx.commit();
} catch (Exception e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
if (s != null) {
s.close();
}
}
}
}
{noformat}
{noformat}
package org.headlesspigs.domainmodel;
public class Invoice {
private Long id;
private int version;
private String number;
private Person receiver;
private Person emitter;
public Invoice() {
super();
}
public Invoice(String number, Person receiver, Person emitter) {
super();
this.number = number;
this.receiver = receiver;
this.emitter = emitter;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getReceiver() {
return receiver;
}
public void setReceiver(Person receiver) {
this.receiver = receiver;
}
public Person getEmitter() {
return emitter;
}
public void setEmitter(Person emitter) {
this.emitter = emitter;
}
}
{noformat}
{noformat}
<?xml version="1.0" encoding="WINDOWS-1251"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.headlesspigs.domainmodel">
<class name="Invoice" table="TEST_INVOICE">
<id name="id" column="ID" type="long"
unsaved-value="0">
<generator class="native" />
</id>
<version name="version" column="VERSION"
type="integer"></version>
<property name="number" type="string"
column="INVOICE_NUMBER"></property>
<many-to-one name="emitter" class="Person"
column="ID_EMITTER_PERSON"
cascade="all">
</many-to-one>
<many-to-one name="receiver" class="Person"
column="ID_RECEIVER_PERSON"
cascade="all">
</many-to-one>
</class>
</hibernate-mapping>
{noformat}
{noformat}
package org.headlesspigs.domainmodel;
public class Person {
private Long id;
private int version;
private String name;
public Person() {
}
public Person(String name) {
super();
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
{noformat}
{noformat}
package org.headlesspigs.domainmodel;
public class WorkingPerson extends Person {
private WorkingPerson referee;
public WorkingPerson() {
}
public WorkingPerson(String name) {
super(name);
}
public WorkingPerson(String name, WorkingPerson referee) {
this(name);
this.referee = referee;
}
public WorkingPerson getReferee() {
return referee;
}
public void setReferee(WorkingPerson referee) {
this.referee = referee;
}
}
{noformat}
{noformat}
<?xml version="1.0" encoding="WINDOWS-1251"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.headlesspigs.domainmodel">
<class name="Person" table="TEST_PERSON">
<id name="id" column="ID" type="long"
unsaved-value="0">
<generator class="native" />
</id>
<discriminator column="TYPE" type="string"/>
<version name="version" column="VERSION"
type="integer"></version>
<property name="name" type="string"
column="NAME"></property>
<subclass name="WorkingPerson" discriminator-value="WORKING">
<many-to-one name="referee" class="WorkingPerson"
column="ID_REFEREE"></many-to-one>
</subclass>
</class>
</hibernate-mapping>
{noformat}
getEntityName() throws org.hibernate.TransientObjectException: proxy
was not associated with the session
--------------------------------------------------------------------------------------------------------
Key: HHH-3230
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-3230
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.2.2
Environment: Mac OS X, JDK 1.5
Reporter: Howard M. Lewis Ship
Attachments: Debugging output from IDEA.jpg, NarrowingProxyTestCase.zip
I'm retrieving an entity that contains a OneToMany relationship.
The master entity is retrieved, within a transaction, via
Session.get(Class,Serializable).
@Entity
public class MapUnitSurvey extends ActiveDO
{
@ManyToOne(fetch = FetchType.LAZY)
private VegetationType vegetationType;
}
@Entity
public class VegetationType extends AbstractEnum
{
}
ActiveDO and AbstractEnum are abstract base classes with @MappedSuperclass.
I retrieve the vegationType:
VegetationType type = survey.getVegetationType();
Then I need the type's entity name
String entityName = session.getEntityName(type);
This fails with the TransientObjectException.
Inspecting with the debugger, I see that type is a CGLIB-enhanced proxy, and that
there's a fully initialized bean in the target field of the proxy. I'll attach a
screenshot of some debugging data.
In summary; the entity was retrieved via a lazy fetch, appears the be correct, seems to
be in the session and yet the exception occurs.
I've tried to resolve this by re-fetching the object from the session, and a few
other tries, with no luck.
--
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....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira