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?

+3


source to share


1 answer


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.

+2


source







All Articles