To solve this Hibernate issue you may be able to use an XmlAdapter. The XmlAdapter would look something like where the logic in the marshal method is to convert from the proxy to the real object:
package forum6838323;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AddressAdapter extends XmlAdapter<Address, Address> {
@Override
public Address unmarshal(Address v) throws Exception {
return v;
}
@Override
public Address marshal(Address v) throws Exception {
// TODO Auto-generated method stub
return null;
}
}
You configure the XmlAdapter as follows:
public class User {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address")
@XmlJavaTypeAdapter(AddressAdapter.class)
public Address getAddress() {
return address;
}
}
If you need to pass an initialized XmlAdapter to the JAXB marshaller, you can do that as well, see the following for an example:
Alternative Using EclipseLink JPA
Note: The lazy loading in EclipseLink JPA does not cause this issue:
User
package forum6838323;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@Entity
@Table(name="users")
@XmlRootElement
public class User {
private int id;
Address address;
@Id
@XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address
package forum6838323;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("ADDRESS")
@XmlSeeAlso(CoolAddress.class)
public class Address {
private int id;
private String street;
@Id
@XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
CoolAddress
package forum6838323;
import javax.persistence.*;
@Entity
@DiscriminatorValue("COOL")
public class CoolAddress extends Address {
private String something;
public String getSomething() {
return something;
}
public void setSomething(String something) {
this.something = something;
}
}
Demo
package forum6838323;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Forum6838323");
EntityManager em = emf.createEntityManager();
User user = em.find(User.class, 2);
System.out.println("user.address BEFORE marshal: " + user.address);
JAXBContext jc = JAXBContext.newInstance(User.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(user, System.out);
System.out.println("user.address AFTER marshal: " + user.address);
}
}
Output
You can see from the output that the address value is being lazily loaded since the field is null before the marshal and populated afterwards:
user.address BEFORE marshal: null
[EL Finest]: 2011-07-27 11:47:13.118--ServerSession(23503403)--Thread(Thread[main,5,main])--Execute query ReadObjectQuery(name="Forum6838323" referenceClass=Address )
[EL Finest]: 2011-07-27 11:47:13.118--ServerSession(23503403)--Connection(10272075)--Thread(Thread[main,5,main])--Connection acquired from connection pool [default].
[EL Fine]: 2011-07-27 11:47:13.118--ServerSession(23503403)--Connection(10272075)--Thread(Thread[main,5,main])--SELECT ID, TYPE, STREET, SOMETHING FROM ADDRESS WHERE (ID = ?)
bind => [2]
[EL Finest]: 2011-07-27 11:47:13.118--ServerSession(23503403)--Connection(10272075)--Thread(Thread[main,5,main])--Connection released to connection pool [default].
[EL Finest]: 2011-07-27 11:47:13.118--UnitOfWork(6131844)--Thread(Thread[main,5,main])--Register the existing object forum6838323.CoolAddress@109ea96
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user id="2">
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="coolAddress" id="2">
<street>2 B Road</street>
<something>Cool Road</something>
</address>
</user>
user.address AFTER marshal: forum6838323.CoolAddress@83b1b