1

AbstractItem別のクラスのフィールドとして使用されるという名前の抽象クラスがあるとします。XStreamを使用してXMLを生成する場合、要素タグをのインスタンスの具体的な実装に基づいて作成する必要がありますAbstractItem

私が得るもの:

<Test>
  <item class="Item1" name="name 1" description="description 1"/>
</Test>

私が欲しいもの:

<Test>
  <Item1 name="name 1" description="description 1"/>
</Test>

XStream次のようにして、インスタンスにエイリアスを設定してみました。

stream.alias("Item1", Item1.class);

また、以下を使用します。

stream.aliasType("Item1", Item1.class);

上記のいずれも機能しませんでした。


わかりやすくするために、上記の実行可能な例を次に示します。

Test.java

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("Test")
public class Test {

    public AbstractItem item;   

    public static void main(String[] args){

        Test t1 = new Test();
        Item1 item1 = new Item1();
        item1.name = "name 1";
        item1.description = "description 1";
        t1.item = item1;

        XStream stream = new XStream();
        stream.setMode(XStream.NO_REFERENCES);
        stream.autodetectAnnotations(true);
        stream.alias("Item1", Item1.class);

        System.out.println(stream.toXML(t1));
    }
}

AbstractItem.java

import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

public abstract class AbstractItem {
    @XStreamAsAttribute
    public String name;
}

Item1.java

import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

public class Item1 extends AbstractItem {
    @XStreamAsAttribute
    public String description;
}


更新: コンバータークラスを使用してこれを実行しようとしましたが、それでも正しくありません:

stream.registerConverter(
        new Converter(){

            @Override
            public boolean canConvert(Class type) {
                if (AbstractItem.class.isAssignableFrom(type)){
                    return true;
                }
                return false;
            }

            @Override
            public void marshal(Object source, HierarchicalStreamWriter writer,
                    MarshallingContext context) {
                AbstractItem item = (AbstractItem)source;
                if(source instanceof Item1){
                    writer.startNode("Item1");
                    writer.addAttribute("description",((Item1)item).description);
                } else if(source instanceof Item2){
                    writer.startNode("Item2");
                    writer.addAttribute("description", ((Item2)item).description);
                } else {
                    writer.startNode("Item");
                }
                writer.addAttribute("name", item.name);
                writer.endNode();
            }

            @Override
            public Object unmarshal(HierarchicalStreamReader reader,
                    UnmarshallingContext context) {
                // TODO Auto-generated method stub
                AbstractItem item = null;
                String nodeName = reader.getNodeName();
                if (nodeName.equals("Item1")){
                    item = new Item1();
                    ((Item1)item).description = reader.getAttribute("description");
                } else if (nodeName.equals("Item2")){
                    item = new Item2();
                    ((Item2)item).description = reader.getAttribute("description");
                }  
                item.name = reader.getAttribute("name");
                return item;
            }
        });

私が今得た結果は次のとおりです。

<Test>
  <item class="Item1">
    <Item1 description="description 1" name="name 1"/>
  </item>
</Test>
4

2 に答える 2

1

これを実現する唯一の方法は、要素タグを操作するオブジェクトを含むクラスのカスタムコンバーターを使用することです。質問の例では、クラスのカスタムコンバーターであり、次のTestようになります。

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class BasicConverter implements Converter {

    @Override
    public boolean canConvert(Class type) {
        return Test.class.isAssignableFrom(type);
    }

    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer,
            MarshallingContext context) {
        if (((Test) source).item instanceof Item1) {
            writer.startNode("Item1");
            writer.addAttribute("description", ((Item1)((Test) source).item).description);
        } else if (((Test) source).item instanceof Item2) {
            writer.startNode("Item2");
            writer.addAttribute("description", ((Item2)((Test) source).item).description);
        }
        writer.addAttribute("name", ((Test) source).item.name);
        writer.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader,
            UnmarshallingContext context) {
        Test test = new Test();

        reader.moveDown();
        String nodeName = reader.getNodeName();
        AbstractItem item = null;       
        if (nodeName.equals("Item1")) {
            item = new Item1();
            ((Item1)item).description = reader.getAttribute("description");
        } else if (nodeName.equals("Item2")) {
            item = new Item2();
            ((Item2)item).description = reader.getAttribute("description");
        }   
        item.name = reader.getAttribute("name");    
        ((Test)test).item = item;
        reader.moveUp();
        return test;
    }
}

これは私が上で探していた出力を与えますが、私にとっては本当に満足のいくものではありません。その理由は、これを使用する必要のある実際のクラスには、独自のカスタムコンバーター、カスタムエイリアスなどを使用するフィールドがたくさんあるためです。さらに、で定義されているものを除いて、Testクラスのすべてのアノテーションが基本的に無視されます。クラスレベル。さらに、クラスが大きくなるにつれて、これらの新しいフィールドを処理するためにこのコンバーターを更新する必要があります。そうしないと、それらが含まれます。

理想的には、特定のフィールドを除いて、注釈によって定義されたとおりにすべてを実行するコンバーターが必要です。現在、私が知っているものはありません。私が行っているのは、com.thoughtworks.xstream.converters.reflection.ReflectionConverterこれを達成するためにクラスを拡張することです。しかし、それは私が特に気にかけている基礎となる実装からより多くのコードをコピーする必要があります。

于 2013-02-05T21:26:21.673 に答える
0

XStreamでも同じ問題に直面しています。私は以前、リフレクションを使用してxmlを読み取るCommonsダイジェスターを使用しました。これにより、xmlを読み取るときに要求する機能が提供されます。欠点は、xmlを書き込めないことです。Javaクラスで何も変更する必要がなく(アノテーションやコンバーターのものがない)、xmlを解析するためのルールを設定するのは非常に簡単であるため、ダイジェスターを好みました。ただし、XStreamまたはJaxbから得られるすべての機能を備えているわけではありません。今のところ、XStream(またはJaxb)を使用してこの問題を解決する必要があるため、必要なコンバーターを作成する必要があると思います。あなたの例をありがとう。

于 2013-10-25T06:56:25.470 に答える