2011-07-27 12 views
6

Trong vài ngày qua, tôi đã cố gắng hỗ trợ cho XML marshalling/unmarshalling của một mô hình Hibernate, sử dụng MOXy JAXB. Đang cố gắng để làm điều này, tôi đã gặp phải một vấn đề với các đối tượng proxy hibernates. xem xét cái gì đó như:(moxy) jaxb marshaling và hibernate proxy objects

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; 
    } 
} 

Tôi đã cố gắng để ánh xạ mã này sử dụng MOXY JAXB theo cách sau:

@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; 
    } 
} 

Vấn đề của tôi là ngủ đông mà instantiates một đối tượng proxy của địa chỉ thu được bằng cách gọi getAddress() trên một Người dùng. Sau đó, khi JAXB cố gắng sắp xếp đối tượng, nó không thể tìm ra rằng nó thực sự là một CoolAddress mà nó đang cố gắng sắp xếp, kết quả là các thuộc tính trong CoolAddress không được sắp xếp lại.

Tôi có googled/coi là giải pháp khả thi sau:

  • Trong một cách nào đó nhận được một cuộc gọi lại từ JAXB, cho phép tôi thay thế các đối tượng được marshaled với người khác. Điều này sẽ cho phép tôi có được đối tượng thực sự từ proxy.
  • Chạm vào tất cả các đối tượng trong mô hình sẽ làm cho việc chụp ảnh thực sự trở nên hibernate. Tôi đã không thể tìm thấy bất kỳ cách thông minh nào làm việc này ngoài việc chạy thủ công thông qua tất cả các thuộc tính không tạm thời, điều này thật tẻ nhạt.
  • Đặt ngủ đông để sử dụng tính năng tìm nạp mong muốn trong phiên tôi sắp xếp các mô hình.

Tôi đang tìm đề xuất thay thế hoặc nếu một trong các đề xuất ở trên là có thể (và dễ) để triển khai. Bất kỳ trợ giúp được đánh giá cao :).

+0

'CoolAddress' extend' Address'? –

+0

Có, xin lỗi. Tôi đã quên viết điều đó. –

Trả lời

6

Để giải quyết vấn đề Hibernate này, bạn có thể sử dụng XmlAdapter.Các XmlAdapter sẽ giống như nơi logic trong phương pháp soái là để chuyển đổi từ các proxy để các đối tượng thực:

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; 
    } 

} 

Bạn cấu hình XmlAdapter như sau:

public class User { 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "address") 
    @XmlJavaTypeAdapter(AddressAdapter.class) 
    public Address getAddress() { 
     return address; 
    } 
} 

Nếu bạn cần phải vượt qua một XmlAdapter khởi tạo các marshaller JAXB, bạn có thể làm điều đó là tốt, xem phần dưới đây cho một ví dụ:


Alternative Sử dụng EclipseLink JPA

Lưu ý: tải lười biếng trong EclipseLink JPA không gây vấn đề này:

tài

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; 
    } 

} 

Địa chỉ

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

Bạn có thể thấy từ kết quả mà các địa chỉ val ue đang được tải xuống một cách lười biếng vì trường này là null trước khi soái và cư trú sau đó:

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 [email protected] 
<?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: [email protected] 
+1

Hơn bạn cho một câu trả lời rất tốt đẹp. –