2011-07-27 11 views
6

W ciągu ostatnich kilku dni starałem się wspierać XML marszu/unmarshalling modelu Hibernate, przy użyciu MOXy JAXB. Próbując to zrobić, natknąłem się na problem z obiektami proxy w trybie hibernacji. rozważyć coś takiego:(moxy) jaxb marshaling i hibernacji obiektów proxy

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

Próbowałem map ten kod przy użyciu Moxy JAXB w następujący sposób:

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

Moim problemem jest to, że hibernacja instancję obiektu proxy adresu uzyskać dzwoniąc getAddress() dla użytkownika. Następnie, gdy JAXB spróbuje sondować obiekt, nie może stwierdzić, że faktycznie jest to CoolAddress, który próbuje przeprowadzić, co powoduje, że właściwości w CoolAddress nie są marnowane.

Mam google/uwzględniono następujące rozwiązania:

  • w jakiś sposób dostać zwrotnego z JAXB, pozwalając mi wymienić obiektu marshaled z innym. To pozwoliłoby mi uzyskać prawdziwy obiekt z proxy.
  • Dotknij wszystkich obiektów w modelu, które spowodują, że hibernacja pobierze prawdziwe obiekty. Nie byłem w stanie znaleźć żadnej mądrej metody robienia tego poza ręcznym przeglądaniem wszystkich nieprzejściowych właściwości, co jest ciche i żmudne.
  • Ustaw hibernację, aby korzystać z szybkiego pobierania w sesji. Mam zamiar przeprowadzić modelowanie.

Poszukuję alternatywnych sugestii lub jeśli jedna z powyższych sugestii jest możliwa (i łatwa) do wdrożenia. Każda pomoc jest doceniana :).

+0

Czy "CoolAddress" rozszerza "adres"? –

+0

Tak, przepraszam. Zapomniałem to napisać. –

Odpowiedz

6

Aby rozwiązać ten problem ze stanem hibernacji, może być możliwe użycie XmlAdapter.XmlAdapter będzie wyglądać gdzie logika w metodzie marszałkowskiego jest konwersja z serwera proxy do rzeczywistego obiektu:

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

} 

skonfigurować XmlAdapter następująco:

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

Jeśli trzeba przejść zainicjowany XmlAdapter do naziemnego JAXB, można to zrobić również znaleźć w następujących miejscach na przykład:


alternatywna Korzystanie EclipseLink JPA

Uwaga: leniwy załadunku w EclipseLink WZP nie powoduje ten problem:

Użytkownika

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

} 

Adres

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

} 

Wyjście

Widać z wyjścia że val adres ue jest ładowany leniwie, ponieważ pole jest puste przed marszałkiem i zaludnione później:

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

Niż za bardzo dobrą odpowiedź. –