1

Xストリームを使用しています。現時点では、XStream を別のものに置き換えるのは簡単ではありません。

インターフェイス (MyInterface) と、そのインターフェイスを実装するいくつかのサブクラスがあります (以下のサンプル コードでは、MyImplementation と呼ばれるものがあります)。

サブクラスのインスタンスをシリアライズおよびデシリアライズしたい。class 属性を XML に入れると、問題なくデシリアライズできることがわかりました。

<myInterfaceElement class="myPackage.MyImplementation">
  <field1>value1</field1>
  <field2>value2</field2>
</myInterfaceElement>

しかし、XStream に class 属性を書き込む方法がわかりません。シリアル化するときに XStream に class 属性を含めるにはどうすればよいですか? または、要素名がすべての実装で同じになり、各サブクラスが独自のフィールドを定義できるように、クラス階層をシリアライズ/デシリアライズする別の方法はありますか?

MyInterface、MyImplementation、それを機能させようとする JUnit テスト ケースの例を次に示します。deserializeWithClassAttribute テストはパスしますが、classAttributeSetInResult は失敗します。


package myPackage;

public interface MyInterface {

}

package myPackage;

public class MyImplementation implements MyInterface {
    public String field1;
    public String field2;

    public MyImplementation(String field1, String field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

package myPackage;
import org.junit.Test;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

import static org.junit.Assert.*;


public class xstreamTest {
    @Test
    public void classAttributeSetInResult() {
        MyInterface objectToSerialize = new MyImplementation("value1", "value2");

        final XStream xStream = new XStream(new DomDriver());
        xStream.alias("myInterfaceElement", MyInterface.class);

        String xmlResult = xStream.toXML(objectToSerialize).toString();

        String expectedResult = 
"<myInterfaceElement class=\"myPackage.MyImplementation\">\n" +
"  <field1>value1</field1>\n" +
"  <field2>value2</field2>\n" +
"</myInterfaceElement>";

        assertEquals(expectedResult, xmlResult);
    }

    @Test
    public void deserializeWithClassAttribute() {
        String inputXmlString = 
"<myInterfaceElement class=\"myPackage.MyImplementation\">\r\n" +
"  <field1>value1</field1>\r\n" +
"  <field2>value2</field2>\r\n" +
"</myInterfaceElement>";

        final XStream xStream = new XStream(new DomDriver());

        MyInterface result = (MyInterface)xStream.fromXML(inputXmlString);
        assertTrue("Instance of MyImplementation returned", result instanceof MyImplementation);

        MyImplementation resultAsMyImplementation = (MyImplementation)result;
        assertEquals("Field 1 deserialized", "value1", resultAsMyImplementation.field1);
        assertEquals("Field 2 deserialized", "value2", resultAsMyImplementation.field2);
    }
}
4

2 に答える 2

2

私は次のようにしてこれを理解しました(Converterを使用するヒントについてMcDに感謝します):

  1. ReflectionConverter を拡張するカスタム Converter を追加します。

    package myPackage;
    
    import com.thoughtworks.xstream.converters.MarshallingContext;
    import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
    import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
    import com.thoughtworks.xstream.mapper.Mapper;
    
    public class MyInterfaceConverter extends ReflectionConverter {
    
        public MyInterfaceConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
            super(mapper, reflectionProvider);
        }
    
        @Override
        public void marshal(Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) {
            writer.addAttribute("class", original.getClass().getCanonicalName());
            super.marshal(original, writer, context);
        }
    
        @SuppressWarnings("rawtypes")
        @Override
        public boolean canConvert(Class type) {
            return MyInterface.class.isAssignableFrom(type);
        }
    
    }
    
  2. xStream をセットアップするときに新しいコンバーターを登録します。

    @Test
    public void classAttributeSetInResult() {
        MyInterface objectToSerialize = new MyImplementation("value1", "value2");
    
        final XStream xStream = new XStream(new DomDriver());
        xStream.alias("myInterfaceElement", MyImplementation.class);
        xStream.registerConverter(new MyInterfaceConverter(xStream.getMapper(), xStream.getReflectionProvider()));
    
        String xmlResult = xStream.toXML(objectToSerialize).toString();
    
        String expectedResult = 
            "<myInterfaceElement class=\"myPackage.MyImplementation\">\n" +
            "  <field1>value1</field1>\n" +
            "  <field2>value2</field2>\n" +
            "</myInterfaceElement>";
    
        assertEquals(expectedResult, xmlResult);
    }
    

うまくいけば、これは将来誰かを助けるでしょう。誰かがより良いアイデアを持っている場合は、私に知らせてください!

于 2013-08-02T20:07:59.030 に答える