5

JPA と JAXB に基づいて REST API を実装しました。

私は大まかに次のようなクラスを持っています(非常に単純化されています):

@Entity
@XmlRootElement
...
public class Thing {
    @Id
    @GeneratedValue
    ...
    @XmlAttribute
    @XmlID
    @XmlJavaTypeAdapter(JAXBLongAdapter.class)
    private Long id;
    ...
}

Hibernate (私の現在の JPA プロバイダー) は id 値として数値を生成しますが、それらは当然 1 つの型 (この例では Thing) に対してのみ一意です。

現在、XSD は、xsd:id (@XmlID) は NCString であり、単純な数値にすることはできないため、JAXBLongAdapter の数値の先頭に「_」を追加しました。-「_1」のように

今、スキーマバリデータは不平を言います:

[org.xml.sax.SAXParseException: cvc-id.2: There are multiple occurrences of ID value '_1'.]

これを正しく理解している場合、xsd:ID 要素には、xml ドキュメント内でグローバルに一意の (文字列) 値が必要です。しかし、これはデータベースで ID を使用する一般的な方法とは正反対です。

私は今何をしますか?次の3つのことを考えました。

  • タイプ固有のプレフィックスを使用して、タイプごとに JAXBLongAdapter を作成しますか?
  • 別の JPA id ジェネレーター、おそらく UUID を使用していますか? - でもどれ?
  • @XmlID と @XmlIDREF の使用を停止すると、冗長性と全体的な混乱が生じます。

別の ID を使用するには、データベース スキーマを変更する必要があるようです。- しかし、ID は URL に表示されるため、ID が短いままであるとよいでしょう。

私の質問: 比較的高速でグローバルにユニークな ID ジェネレーターはありますか? または、これに取り組む別の方法はありますか?

編集:

このハックはちょっとうまくいき、JPA IDはそのまま残ります。

@XmlID
@XmlAttribute(name="id")
private String getXmlID(){
    return String.format("%s-%s", this.getClass().getSimpleName(), this.getId().toString());
}

private void setXmlID(String xmlid){
    String prefix = String.format("%s-", this.getClass().getSimpleName());
    if(xmlid.startsWith(prefix)){
        this.id = Long.parseLong(xmlid.substring(prefix.length()));
    }else{
        throw new IllegalArgumentException(xmlid+" does not look like "+prefix+"###");
    }
}

JAXB アノテーションをフィールドから XmlID 専用のプライベート ゲッター/セッターに移動する。

4

2 に答える 2

2

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

答えはどうあるべきか

答えは、とプロパティ@XmlSchemaTypeの両方で注釈を使用することです。残念ながら、JAXB RI はその組み合わせを活用しておらず、EclipseLink MOXy は. 次の MOXy バグを入力しました。このアプローチに興味がある場合は修正できます。@XmlID@XmlIDREF@XmlID

従業員

package forum11791735;

import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {

    @XmlID
    @XmlJavaTypeAdapter(JAXBLongAdapter.class)
    @XmlSchemaType(name="long")
    private Long id;

    @XmlIDREF
    @XmlSchemaType(name="long")
    private Employee manager;

    @XmlElement(name="report")
    private List<Employee> reports;

}

回避策

表示されているエラーは、スキーマの検証が原因のようです。これらのエラーを無視するためValidationEventHandlerに、スキーマの検証を無効にするか、 を設定することはできますか?Unmarshaller

代替案

@XmlID/を使用して双方向の関係をマッピングしている場合は、MOXy の拡張機能@XmlIDREFに興味があるかもしれません。@XmlInverseReference

于 2012-08-03T13:22:46.137 に答える
2

それはまさに私がしばらくの間やっていたことです。

@XmlIDマーシャリングされたときに、このドメイン オブジェクトが実際に何を意味するのか自問してみてください。

私はかつて、JAXB の循環問題を解決できると考え@XmlIDていました。@XmlIDREF

JPA エンティティと JAXB アノテーションを使って私が行っていることを次に示します。

あきらめないでくださいsimple JPA @Id。それがJPAの核心です。

@XmlRootElement
public class Parent {

    @Id
    @XmlAttribute
    private Long id;

    @OneToMany
    @XmlElement(name = "child")
    @XmlElementWrapper
    private Collection<Child> children;
}


@XmlRootElement
public class Child {

    @XmlAttribute
    private Long getParentId() {
        return parent.getId();
    }

    @Id
    @XmlAttribute
    private Long id;

    @ManyToOne
    @XmlTransient // for preventing infinite circular problem
    private Parent parent;
}
于 2012-08-03T12:34:15.860 に答える