2

このクラスのインスタンスはラージ オブジェクト グラフの一部であり、オブジェクト グラフのルートにはありません。

public class Day
{
    public Day(LocalDate date, List<LocalTime> times)
    {
        this.date = date;
        this.times = times;
    }

    public Day()
    {
        this(null, null);
    }

    public LocalDate getDate()
    {
        return date;
    }

    public List<LocalTime> getTimes()
    {
        return times;
    }

    private final LocalDate date;

    private final List<LocalTime> times;
}

オブジェクト グラフは、Jersey と JAXB を使用して JSON に変換されます。とにXmlAdapter登録しました。LocalDateLocalTime

問題は、dateプロパティではなくプロパティに対してのみ機能することtimesです。timesこれは、単一の値ではなくリストであるという事実と関係があると思われます。timesでは、Jersey/JAXB に、登録された .xml を使用してリスト内の各要素をマーシャリングするように指示するにはどうすればよいXmlAdapterでしょうか?

アップデート:

スカラープロパティを追加し、JSON で予想される出力を観察することで、スカラー プロパティLocalTimeに対してマーシャリングが実際に機能していることを確認しました。LocalTimeLocalTime

完全を期すために、package-info.java は次のとおりです。

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdapter(value = LocalDateAdapter.class, type = LocalDate.class),
    @XmlJavaTypeAdapter(value = LocalTimeAdapter.class, type = LocalTime.class)
})
package same.package.as.everything.else;

LocalDateAdapter:

public class LocalDateAdapter extends XmlAdapter<String, LocalDate>
{
    @Override
    public LocalDate unmarshal(String v) throws Exception
    {
        return formatter.parseLocalDate(v);
    }

    @Override
    public String marshal(LocalDate v) throws Exception
    {
        return formatter.print(v);
    }

    private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMdd");
}

LocalTimeAdapter:

public class LocalTimeAdapter extends XmlAdapter<String, LocalTime>
{
    @Override
    public LocalTime unmarshal(String v) throws Exception
    {
        return formatter.parseLocalTime(v);
    }

    @Override
    public String marshal(LocalTime v) throws Exception
    {
        return formatter.print(v);
    }

    private final DateTimeFormatter formatter = DateTimeFormat.forPattern("HHmm");
4

1 に答える 1

4

クラスのXmlAdapterは、そのタイプのマップされたフィールド/プロパティに適用されます。コレクションの場合は、コレクション内の各アイテムに適用されます。以下の例は、これが機能することを証明しています。例をスタンドアロンで XML に実行して、マッピングをそのように検証してみましたか。問題は具体的なもの以外にあると思われますXmlAdapter

文字列アダプター

以下XmlAdapterは、アンマーシャリング操作で aStringを小文字に変換し、マーシャリング時に大文字に変換します。

package forum14569293;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class StringAdapter extends XmlAdapter<String, String> {

    @Override
    public String unmarshal(String v) throws Exception {
        return v.toLowerCase();
    }

    @Override
    public String marshal(String v) throws Exception {
        return v.toUpperCase();
    }

}

パッケージ情報

あなたの質問と同じように、パッケージ レベルの@XmlJavaTypeAdapters注釈を使用してXmlAdapter. これにより、このパッケージ内XmlAdapterのすべてのマップされたプロパティにこれが登録されます (参照: http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html )。String

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
})
package forum14569293;

import javax.xml.bind.annotation.adapters.*;

Day以下は、 2 つのマップされたプロパティを持つクラスに似たサンプル ドメイン モデルです。1 つ目は typeStringで、2 つ目はList<String>. クラスについて気付いたことの 1 つDayは、メソッドしかないことですget@XmlElementこれは、マップされたプロパティと見なすために、JAXB impl に注釈を追加する必要があることを意味します。

package forum14569293;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Root {

    public Root(String foo, List<String> bar) {
        this.foo = foo;
        this.bar = bar;
    }

    public Root() {
        this(null, null);
    }

    @XmlElement
    public String getFoo() {
        return foo;
    }

    @XmlElement
    public List<String> getBar() {
        return bar;
    }

    private final String foo;
    private final List<String> bar;

}

デモ

package forum14569293;

import java.util.*;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        List<String> bar = new ArrayList<String>(3);
        bar.add("a");
        bar.add("b");
        bar.add("c");
        Root root = new Root("Hello World", bar);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);

    }

}

出力

以下は、デモ コードを実行した場合の出力です。すべての文字列がXmlAdapter.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <bar>A</bar>
    <bar>B</bar>
    <bar>C</bar>
    <foo>HELLO WORLD</foo>
</root>

アップデート

ありがとう。試してみたところ、XML は 1 つの空のタグのみで構成されていました。これは、JAXB が気に入らない POJO モデルに関する何かがあることを意味します。(おそらく、シリアライズ可能である必要がありますか?)

JAXB では、POJO が を実装する必要はありませんSerializable

これは興味深いことです。これは、JAXB が果たす唯一の役割は、そのアノテーションとその他のインターフェース (XmlAdapter など) を JSON (デ) シリアライザーに貸与することであり、それで関係が終了することを示しているように思われるからです。

これは、JSON バインディング レイヤーとして使用されているものによって異なります。JAXB (JSR-222)仕様はJSON バインディングをカバーしていないため、このタイプのサポートは仕様を超えています。EclipseLink JAXB (MOXy) は、ネイティブの JSON バインディング (私は MOXy のリーダーです) を提供し、次のようなことができます。

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(root, System.out);

XmlAdapterを考慮した次の出力を取得します。

{
   "bar" : [ "A", "B", "C" ],
   "foo" : "HELLO WORLD"
}

それでも、機会があれば、JAXB に XML を生成させるためにできる限りのことをするつもりです。

あなたが見ているのは JAXB の問題ではなく、あなたが使用している JSON バインディング レイヤーの問題であるとは思わないので、これは役に立ちます。

于 2013-01-29T10:29:05.507 に答える