XStream 使用 NamedMapConverter 序列化自定义地图

XStream serialize custom Map with NamedMapConverter

我正在成功序列化包含 HashMap<String, String>NamedMapConverterBase class。我的要求已更改,我需要将 HashMap 更改为扩展 HashMap<String, String> 的自定义 StringDictionary class。

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

在 Android 上使用 XStream 1.4.7。


需要xml输出:

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

Base class 使用 HashMapXStream 配置产生以上输出

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);

使用修改后的Baseclass

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 class。

以下代码将为修改后的 Base class:

生成所需的 xml 输出
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 class 传递给 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>