在过去的几天里,我尝试使用MOXy JAXB来支持Hibernate模型的XML编组/解组。试图这样做,我遇到了hibernates代理对象的问题。 考虑类似的事情:
public class User {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address")
public Address getAddress() {
return address;
}
}
public abstract class Address {
// Something
}
public class CoolAddress extends Address {
public String getSomething() {
return something;
}
}
我尝试使用MOXy JAXB以下列方式映射此代码:
@XmlAccessorType(XmlAccessType.NONE)
public class User {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address")
@XmlElement
public Address getAddress() {
return address;
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso(CoolAddress.class)
public abstract class Address {
// Something
}
@XmlAccessorType(XmlAccessType.NONE)
public class CoolAddress extends Address {
@XmlElement
public String getSomething() {
return something;
}
}
我的问题是hibernate实例化通过在User上调用getAddress()获得的地址的代理对象。然后,当JAXB试图封送该对象时,它无法发现它实际上是一个正在尝试封送的CoolAddress,这导致CoolAddress中的属性没有被封送。
我用google搜索/考虑了以下可能的解决方案:
我正在寻找其他建议,或者上述建议之一是否可行(并且易于实施)。任何帮助表示赞赏:)。
答案 0 :(得分:6)
要解决此Hibernate问题,您可以使用XmlAdapter
。 XmlAdapter看起来就像marshal方法中的逻辑从代理转换为真实对象的地方:
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;
}
}
您可以按如下方式配置XmlAdapter
:
public class User {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address")
@XmlJavaTypeAdapter(AddressAdapter.class)
public Address getAddress() {
return address;
}
}
如果您需要将初始化的XmlAdapter传递给JAXB编组器,您也可以这样做,请参阅以下示例:
替代使用EclipseLink JPA
注意:EclipseLink JPA中的延迟加载不会导致此问题:
用户强>
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;
}
}
<强>地址强>
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;
}
}
<强>演示强>
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);
}
}
<强>输出强>
您可以从输出中看到地址值被延迟加载,因为该字段在编组之前为空并在之后填充:
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