2

オブジェクトを XML として返す RESTful Jersey Web サービスがあります。返されたオブジェクトのメンバーの 1 つは、実行時までわからないいくつかの可能な型 (すべて共通の基本クラスから派生したもの) の 1 つです。以下に示すように、このメンバーを出力 XML に表示することはできません。

問題をいくつかのサンプルクラスに減らしました:

@XmlRootElement
public abstract class Animal {

    public String type;

    public Animal() {
        type = "?";
    }

    public Animal(String type) {
        this.type = type;
    }
}

@XmlRootElement
public class Mammal extends Animal {

    public String name;

    public Mammal() {
        name = "?";
    }

    public Mammal(String type, String name) {
        super(type);
        this.name = name;
    }
}

@XmlRootElement
public class Zoo {
    private Animal creature;

    @XmlElementRef
    public Animal getCreature() {
        return creature;
    }

    public void setCreature(Animal creature) {
        this.creature = creature;
    }

    public Zoo() {
        creature = new Mammal("Mouse", "Mickey");
    }
}

@Path("/test")
public class TestResource {

    @GET
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Zoo get() {
        Zoo z = new Zoo();
        return z;
    }
}

サービスを呼び出すと、次の応答が返されます。

<zoo/>

予想されるクリーチャーは含まれません。

メンバ 'creature' の型を Animal (抽象基本クラス) から Mammal (派生クラス) に変更すると、期待どおりの出力が得られますが、それは適切な解決策ではありません。

そこで、次のコードを get() メソッドに追加しました。

    // DIAGNOSTIC CODE: Convert object to XML and send to System.out
    try {
        JAXBContext context = JAXBContext.newInstance(Zoo.class, Mammal.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(z, System.out);
    } catch (JAXBException ex) {
        ex.printStackTrace();
    }

そして今、サービスからのXMLが間違っていますが(空のタグだけです)、コンソールに正しい出力が表示されます:

<?xml version="1.0" encoding="UTF-8"?>
<zoo>
   <mammal>
      <type>Mouse</type>
      <name>Mickey</name>
   </mammal>
</zoo>

さて、その出力を得るために、私は Mammal.class が JAXBContext.newInstance() に渡されたことを確認しなければなりませんでした。 Web サービスによって行われることは、派生した Mammal クラスを認識しないため、オブジェクトを正しくシリアル化できません。それは正しい診断ですか?どうすれば修正できますか?

4

1 に答える 1

2

JAXBContext問題は、ジャージーが戻り値の型から作成するデフォルトがクラスZooを認識しないことです。MammalをプルしAnimalますが、そのサブクラスはプルしません (これを行うための API が存在しないため)。JAXBContextこれが、ロギング目的で を認識した を作成したときに、Mammalすべてが正しく機能した理由です。

解決策 1 - レバレッジ@XmlSeeAlso

この@XmlSeeAlsoアノテーションは、このクラスを処理するときにこれらの他のクラスも処理することを JAXB impl に伝えます。通常、これはマップされたサブクラスを参照するために使用されます。

@XmlRootElement
@XmlSeeAlso({Mammal.class})
public abstract class Animal {

    public String type;

    public Animal() {
        type = "?";
    }

    public Animal(String type) {
        this.type = type;
    }
}

解決策 2 - JAX-RS を活用するContextResolver

この問題はJAXBContext、ジャージーが作成するデフォルトがMammalクラスを認識しないことが原因であると述べました。a を使用して aContextResolverを返すことができますJAXBContext。以下は、 を作成する例へのリンクですContextResolver

于 2013-06-26T15:32:02.960 に答える