XStream serialize custom Map with NamedMapConverter

爱⌒轻易说出口 提交于 2021-02-10 15:15:26

问题


I am successfully serializing my Base class containing HashMap<String, String> with NamedMapConverter. My requirements have changed and I need to change HashMap to custom StringDictionary class that extends HashMap<String, String>.

But after using StringDictionary, my serialization got broken. Is there a way to configure XStream and/or NamedMapConverter to preserve needed xml output without writing custom converters?

Using XStream 1.4.7 on Android.


Required xml output:

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

Base class with HashMap and XStream configuration that produces above output

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

Using modified Base class

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

produces following incorrect xml output:

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

回答1:


It seems that without custom converter above is impossible to achieve. However, in this case custom converter can be provided with only slight tweaking of existing one. Problem lies in NamedMapConverter.canConvert method that has to be overridden to include custom StringDictionary class.

Following code will produce required xml output for modified Base class:

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

Another simpler (but not fully compliant) solution, is to pass StringDictionary class to NamedMapConverter constructor. However this solution will slightly change xml output.

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>


来源:https://stackoverflow.com/questions/32296215/xstream-serialize-custom-map-with-namedmapconverter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!