我已成功将包含BaseHashMap<String, String>类与NamedMapConverter序列化。我的要求已更改,我需要将HashMap更改为扩展StringDictionary的自定义HashMap<String, String>类。

但是在使用StringDictionary之后,我的序列化被破坏了。有没有一种方法可以配置XStream和/或NamedMapConverter以保留所需的xml输出而无需编写自定义转换器?

在Android上使用XStream 1.4.7。



必需的xml输出:

<base>
  <values>
    <val key="123">111</val>
    <val key="abc">aaa</val>
  </values>
</base>


具有BaseHashMap配置的XStream类产生上述输出

public class Base
{
    public Map<String, String> values = new HashMap<>();
}


Base base = new Base();
base.values.put("abc", "aaa");
base.values.put("123", "111");

XStream xs = new XStream();
xs.alias("base", Base.class);
NamedMapConverter c = new NamedMapConverter(xs.getMapper(), "val", "key", String.class, null, String.class, true, false, xs.getConverterLookup());
xs.registerConverter(c);

String s = xs.toXML(base);




使用修改后的Base

public class Base
{
    public Map<String, String> values = new StringDictionary();
}


产生以下不正确的xml输出:

<base>
  <values class="com.test.StringDictionary" serialization="custom">
    <unserializable-parents/>
    <map>
      <default>
        <loadFactor>0.75</loadFactor>
      </default>
      <int>4</int>
      <int>2</int>
      <string>123</string>
      <string>111</string>
      <string>abc</string>
      <string>aaa</string>
    </map>
  </values>
</base>

最佳答案

似乎没有上面的自定义转换器是不可能实现的。但是,在这种情况下,仅需对现有转换器进行一些微调即可提供定制转换器。问题在于NamedMapConverter.canConvert方法,必须重写该方法以包括自定义StringDictionary类。

以下代码将为修改后的xml类生成所需的Base输出:

XStream xs = new XStream();
xs.alias("base", Base.class);

xs.addDefaultImplementation(StringDictionary.class, Map.class);
NamedMapConverter c = new NamedMapConverter(xs.getMapper(), "val", "key", String.class, null, String.class, true, false, xs.getConverterLookup())
{
    public boolean canConvert(Class type)
    {
        if (type.equals(StringDictionary.class)) return true;
        else return super.canConvert(type);
    }
};
xs.registerConverter(c);




另一个更简单(但不完全兼容)的解决方案是将StringDictionary类传递给NamedMapConverter构造函数。但是,此解决方案将略微更改xml输出。

XStream xs = new XStream();
xs.alias("base", Base.class);
NamedMapConverter c = new NamedMapConverter(StringDictionary.class, xs.getMapper(), "val", "key", String.class, null, String.class, true, false, xs.getConverterLookup());
xs.registerConverter(c);


<base>
  <values class="com.test.StringDictionary">
    <val key="123">111</val>
    <val key="abc">aaa</val>
  </values>
</base>

07-26 09:32