3

@XmlElementWrapper(name = "foos")と@XmlElement(name = "foo")の両方で注釈が付けられたクラスのリストセッターがあります。

<foos> </foos>または<foo/>要素を持たないXMLをアンマーシャルすると、セッターが呼び出され、空のリストが渡されます。以下を取得する方法はありますか?:

  • <foos />がない場合は、セッターを呼び出さないでください。または、セッターを呼び出す必要がある場合は、nullを渡します。
  • <foos />が存在するが空の場合、空のリストをセッターに渡します。
  • <foos>に1つ以上の子<foo/>要素がある場合、入力済みリストを渡します。
4

4 に答える 4

3

このユース ケースでは XmlAdapter を使用できます。

input1.xml

がない場合は、setter を呼び出しません。または、setter を呼び出す必要がある場合は、null を渡します。

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <child/>
</root>

input2.xml

が存在するが空の場合、空のリストをセッターに渡します。

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <child>
        <foos/>
    </child>
</root>

input3.xml

1 つ以上の子要素がある場合は、入力済みのリストを渡します。

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <child>
        <foos>
             <foo>Hello World</foo>
       </foos>
   </child>
</root>

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class Root {

    private Child child;

    @XmlJavaTypeAdapter(ChildAdapter.class)
    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
    }

}

import java.util.List;

public class Child {

    private List<String> strings;

    public List<String> getStrings() {
        return strings;
    }

    public void setStrings(List<String> strings) {
        System.out.println("setStrings");
        this.strings = strings;
    }

}

子アダプタ

import java.util.ArrayList;
import java.util.List;

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

public class ChildAdapter extends XmlAdapter<ChildAdapter.AdaptedChild, Child> {

    public static class AdaptedChild {
        public Foos foos;
    }

    public static class Foos {
        public List<String> foo;
    }

    @Override
    public Child unmarshal(AdaptedChild adaptedChild) throws Exception {
        Child child = new Child();
        Foos foos = adaptedChild.foos;
        if(null != foos) {
            List<String> foo = foos.foo;
            if(null == foo) {
                child.setStrings(new ArrayList<String>());
            } else {
                child.setStrings(foos.foo);
            }
        }
        return child;
    }

    @Override
    public AdaptedChild marshal(Child child) throws Exception {
        AdaptedChild adaptedChild = new AdaptedChild();
        List<String> strings = child.getStrings();
        if(null != strings) {
            Foos foos = new Foos();
            foos.foo = strings;
            adaptedChild.foos = foos;
        }
        return adaptedChild;
    }

}

デモ

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        Object o;

        o = unmarshaller.unmarshal(new File("input1.xml"));
        marshaller.marshal(o, System.out);

        o = unmarshaller.unmarshal(new File("input2.xml"));
        marshaller.marshal(o, System.out);

        o = unmarshaller.unmarshal(new File("input3.xml"));
        marshaller.marshal(o, System.out);
    }

}

出力

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <child/>
</root>
setStrings
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <child>
      <foos/>
   </child>
</root>
setStrings
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <child>
      <foos>
         <foo>Hello World</foo>
      </foos>
   </child>
</root>
于 2011-05-20T15:27:28.133 に答える
1

これは、Blaise Doughan の回答のコメントに記載されている合併症に対して機能することになったアダプターです。

public class ListOfFooAdapter extends XmlAdapter<ListOfFooAdapter.Adapted, List<Foo>> {
    @XmlRootElement(name = "foos")
    public static class Adapted {
        public List<Foo> foo;
    }

    @Override
    public List<Foo> unmarshal(Adapted adapted) throws Exception {
        return adapted.foo;
    }

    @Override
    public Adapted marshal(List<Foo> foo) throws Exception {
    if (null == foo) {
            return null;
        } else {
            Adapted adapted = new Adapted();
            adapted.foo = foo;
            return adapted;
        }
    }
}

...要素が XML に存在しない限り、unmarshall メソッドは呼び出されません。

リスト プロパティに次のように注釈を付けました。

@XmlJavaTypeAdapter(ListOfFooAdapter.class)
public List<Foo> getFoos() {
    ...
}

public void setFoos(List<Foo> l) {
    ...
}
于 2011-05-20T17:27:01.097 に答える
1

私は同じ問題を解決しようとしていて、ここのサンプルでかなり長い間遊んでいました。非常に教育的で、彼らに大いに感謝します。

しかし、JDK 6 の JAXB 実装のように成熟したものが XML の要素を理解して、冷淡に空のリストをコードに渡すというのは正しくないように思えました。

JAXB は、まだ空のリストへの参照を使用してセッターを呼び出した、リストにデータを入力していたことが判明しました。そのため、セッター コードが次のようになると、アンマーシャリング フェーズの残りの部分でリストへの後続の更新が行われませんでした。

@XmlElementWrapper(name = "foos")
@XmlElement(name = "foo")
public void setFoos(List<Foo> newFoos) {
    this.foos.clear();
    this.foos.addAll(newFoos);
}

セッターを次のように変更したとき

@XmlElementWrapper(name = "foos")
@XmlElement(name = "foo")
public void setFoos(List<Foo> newFoos) {
    this.foos = newFoos;
}

それはうまくいきました。リストの所有者は事後にリストを変更できるため、他の誰かのリストへのポインターにしがみつくのは常に不安な経験ですが、この場合、問題を修正したのはその変更でした。

JAXB から渡されたリストを繰り返し処理することで、想定を確認しました。確かに、ConcurrentModificationException について不平を言っていました。これは、リストをコードに渡した後、リストが実際に機能していたことを示しています。

于 2011-07-30T05:54:24.370 に答える
0

beforeUnmarshallafterUnmarshallメソッド、またはリスナーにすべてのロジックを配置できUnmarshaller、アンマーシャリングが完了すると実行されます。

詳細については、 https://stackoverflow.com/a/4378648/751200を参照してください。

于 2015-05-14T10:09:08.727 に答える