How to deserialize xml into a map of custom attributes (and their values) using SimpleXml?
I am using SimpleXml .
xml I deserialize looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<test a="1" e="2" f="5"/>
What attributes are a
, e
and f
it is not known at runtime - can also be q
and z
.
Class definition:
@Root (strict = false)
public class Test {
@ElementMap (entry = "test", attribute = true)
public HashMap<String, Integer> map;
}
I expect it Test.map
will contain "a" -> 1
, "b" -> 2
and "f" -> 5
after deserialization.
Instead, I keep getting the exception: unnable to satisfy @org.simpleframework.xml.ElementMap ... on field 'map' ... for class Test ...
(fluff removed - the exception message doesn't provide any further clarification).
I've tried tinkering with various attributes ElementMap
(attachment, not attachment, etc.) but nothing worked so far.
(These values are actually numeric, although this is indirect, and I'd be good with string values to parse them myself if necessary, but I'm not sure if that matters at all.)
What solution?
And if SimpleXml
doesn't suggest any out of the box, what's the suggested workaround?
source to share
I solved it with Converter , which allows manual deserialization.
So now the model:
public class Test {
@Convert (MapConverter.class)
@Element (name = "test")
public HashMap<String, Integer> test;
}
And MapConverter
:
public class MapConverter implements Converter<HashMap<String, Integer>> {
@Override
public HashMap<String, Integer> read(InputNode inputNode) throws Exception {
final HashMap<String, Integer> result = new HashMap<String, Integer>();
for (final String attributeName : inputNode.getAttributes()) {
final String value = inputNode.getAttribute(attributeName).getValue();
result.put(attributeName, Integer.parseInt(value));
}
return result;
}
@Override
public void write(OutputNode outputNode, HashMap<String, Integer> stringIntegerHashMap)
throws Exception {
// not used
}
}
Note that for this you need to pass an instance AnnotationStrategy
to Persister
:
// instead of new Persister()
Persister persister = new Persister(new AnnotationStrategy());
I am not so keen on this solution because
-
I suspect this might be overkill.
-
The initialization
Persister
is done deep inside an existing library that I have to use, so I had to open up the code for it to work at all.
The fact that it Persister
ignores one of the default built-in struct annotations causes a confusing API (although this behavior is documented). But that's a different story.
I wonder if someone came up with something better.
source to share