6

ここ数日、MOXy JAXBを使用して、HibernateモデルのXMLマーシャリング/アンマーシャリングをサポートしようとしました。これを行おうとすると、休止状態のプロキシオブジェクトで問題が発生しました。次のようなものを考えてみましょう。

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

次の方法でMOXyJAXBを使用してこのコードをマップしようとしました。

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

私の問題は、休止状態がユーザーでgetAddress()を呼び出すことによって取得されたアドレスのプロキシオブジェクトをインスタンス化することです。次に、JAXBがオブジェクトをマーシャリングしようとすると、それが実際にマーシャリングしようとしているCoolAddressであることがわかりません。その結果、CoolAddressのプロパティがマーシャリングされません。

私は次の可能な解決策をグーグル/検討しました:

  • 何らかの方法でJAXBからコールバックを取得し、マーシャリングされているオブジェクトを別のオブジェクトに置き換えることができます。これにより、プロキシから実際のオブジェクトを取得できます。
  • モデル内のすべてのオブジェクトをタッチすると、Hibernateが実際のオブジェクトをフェッチします。私は、すべての非一時的なプロパティを手動で実行する以外に、これを行うための賢い方法を見つけることができませんでした。これは、静かで退屈です。
  • モデルをマーシャリングしているセッションで熱心なフェッチを使用するように休止状態を設定します。

私は別の提案を探しています、または上記の提案の1つが実装可能(そして簡単)であるかどうか。どんな助けでも大歓迎です:)。

4

1 に答える 1

7

この休止状態の問題を解決するために、を使用できる場合があります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マーシャラーに渡す必要がある場合は、それも行うことができます。例については、以下を参照してください。


EclipseLinkJPAを使用する代替手段

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

}

出力

出力から、マーシャルの前にフィールドがnullであり、後で入力されるため、アドレス値が遅延ロードされていることがわかります。

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
于 2011-07-27T15:58:56.853 に答える