1

私のセットアップ:

JPAを使用するJBossAS7.1.1、Hibernate(PostgreSQLに接続するため)、RESTEasy、JSONの場合はJackson 1.9.2、XMLの場合はEclipseLink MOXy 2.4.1

GroupUserの2つのエンティティがあります。グループには多くのユーザーが含まれます(1対多)。JPAアノテーション(以下を参照)との双方向の関係を宣言しているので、@JsonManagedReference/ @JsonBackReference(JSONの場合)と@XmlInverseReference(XMLの場合)を使用してサイクルを防ぐ必要があります。これは期待どおりに機能しますが、RESTを介してユーザーを作成しようとすると、XMLを使用しているときにそのユーザーをグループに割り当てることができません。JSONを使用する場合、次のように機能します。

Jackson JSONは機能します(Jane Doeを正常に追加し、彼女をグループ5に配置します):

POST request to /user
Content-Type: application/json
Accept: application/json
Body: {"name":"Jane Doe", "group":{"id":5}}

Response:

{
   "id": 12,
   "name":"Jane Doe"
}

Hibernate: insert into users (group_id, name, id) values (5, 'Jane Doe', 12)

Jacksonでユーザーを追加した後のGroupEndpointの応答は次のとおりです。

GET request to /group
Accept: application/json

Response:

[{"id":5,"name":"My User Group","users":[{"id":12,"name":"Jane Doe"}]}

MOXy XMLが機能しない(Jane Doeが孤立している):

POST request to /user
Content-Type: application/xml
Accept: application/xml
Body: <name>Jane Doe</name><group><id>5</id></group>

Response:

    <user><name>Jane Doe</name><id>12</id></user>

Hibernate: insert into users (group_id, name, id) values (null, 'Jane Doe', 12)

MOXyでユーザーを追加した後のGroupEndpointの応答は次のとおりです。

GET request to /group
Accept: application/xml

Response:

<collection>
  <group><id>5</id><name>My User Group</name></group>
</collection>

私は試しましたが@XmlID@XmlIDREF同じ問題です。 @XmlTransient同様に、マーシャルとアンマーシャルの両方で子と親の関係を無視します。

私の質問:

MOXyが新しいユーザーのグループフィールド(@XmlInverseReferenceとしてマークされている)を無視せずに、ユーザーRESTエンドポイントを介してユーザーをグループに追加するにはどうすればよいですか?

RESTエンドポイントを拡張するか、XmlAdapterを作成するか、カスタムシリアライザーを作成する必要がありますか?さまざまな注釈を使用した簡単な解決策がありませんか? 推奨されるRESTを介してリレーショナルオブジェクトを公開するためのまったく異なるアプローチはありますか? どんな助けでも大歓迎です。

グループエンティティは次のとおりです。

@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Group implements Serializable {
    @Id
    private Long id;

    @Column
    private String name;

    @OneToMany(mappedBy="group", cascade=CascadeType.ALL)
    @JsonManagedReference("group-user")
    private Set<User> users;

    // Omitting getters and setters etc...
}

ユーザーエンティティは次のとおりです。

@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
    @Id
    private Long id;

    @Column
    private String name;

    @ManyToOne
    @JsonBackReference("group-user")
    @XmlInverseReference(mappedBy="users")
    private Group group;

    // Omitting getters and setters etc...
}

ユーザーRESTエンドポイントは次のとおりです。

@Stateful
@Path("/user")
@TransactionAttribute
public class UserEndpoint {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    @POST
    @Consumes({"application/xml","application/json"})
    public User create(User entity) {
        em.joinTransaction();
        em.persist(entity);
        return entity;
    }
}

これがグループRESTエンドポイントです(サイクルを防ぐ必要性を示すために含まれています):

@Stateful
@Path("/group")
@TransactionAttribute
public class GroupEndpoint {
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    @GET
    @Produces({"application/xml","application/json"})
    public List<Group> listAll() {
        final List<Group> results = em.createQuery("SELECT x FROM Group x").getResultList();
        return results;
    }
}

サイクルをテストするために、Jacksonを使用してユーザーを追加した後のGroupEndpointMOXyの応答は次のとおりです。

GET request to /group
Accept: application/xml

Response:

<collection>
  <group>
     <id>5</id>
     <name>My User Group</name>
     <users><id>12</id><name>Jane Doe</name></users>
  </group>
</collection>
4

1 に答える 1

2

注: 私はEclipseLink JAXB(MOXy)のリーダーであり、JAXB(JSR-222)エキスパートグループのメンバーです。

ユースケースのサポートがEclipseLink2.5.0に実装されました。毎晩のレーベル(2013年3月1日から)は以下のリンクからダウンロードできます。

JAVAモデル

現在、MOXyは@XmlInverseReference、関係の両方向での注釈の指定をサポートしています。単独で指定した場合は、マーシャリングの場合と同じように扱われます。@XmlTransient書き込み可能にするには、と組み合わせて使用​​する必要があります@XmlElement

ユーザー

import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;

@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
    @Id
    private Long id;

    @Column
    private String name;

    @ManyToOne
    //@JsonBackReference("group-user")
    @XmlElement
    @XmlInverseReference(mappedBy="users")
    private Group group;

    public Group getGroup() {
        return group;
    }

    // Omitting other getters and setters etc...
}

グループ

import java.io.Serializable;
import java.util.Set;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;

@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Group implements Serializable {
    @Id
    private Long id;

    @Column
    private String name;

    @OneToMany(mappedBy="group", cascade=CascadeType.ALL)
    //@JsonManagedReference("group-user")
    @XmlElement
    @XmlInverseReference(mappedBy="group")
    private Set<User> users;

    public Set<User> getUsers() {
        return users;
    }

    // Omitting other getters and setters etc...
}

デモコード

デモ

以下は、すべてが機能することを証明するために実行できるコードです。XMLのユースケースに加えて、MOXyを使用してJSONを処理することもできます。

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

public class Demo {

    public static void main(String[] args) throws Exception {

        JAXBContext jc = JAXBContext.newInstance(User.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        // XML USE CASE
        StringReader xml = new StringReader("<user><name>Jane Doe</name><group><id>5</id></group></user>");
        User userFromXML = (User) unmarshaller.unmarshal(xml);
        System.out.println(userFromXML.getGroup().getUsers());

        // JSON USE CASE
        StringReader json = new StringReader("{\"name\":\"Jane Doe\", \"group\":{\"id\":5}}");
        unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
        unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
        StreamSource jsonSource = new StreamSource(json);
        User userFromJSON = unmarshaller.unmarshal(jsonSource, User.class).getValue();
        System.out.println(userFromJSON.getGroup().getUsers());
    }

}

出力

以下は、バックポインタが正しく設定されていることを示すデモコードの実行からの出力です。

[forum14844691.User@147ee929]
[forum14844691.User@685c53ff]

詳細については

于 2013-02-13T01:36:58.247 に答える