1

I am trying to serialize some xml data from a public web service into java objects with Simple XML Framework. The problem is that different methods from the service return the same concept with different element names. For example, method A returns element foo like this

<data><Foo>foo value</Foo></data>

whereas method B returns

<data><foo>foo value</foo></data>

and method C returns

<data><FOO>foo value</FOO></data>

Is there any way (a multiple name annotation or so) of getting this xml deserialized into the same class and same element? For example, deserializing the three method's results into the same "foo" element in three different "Foo" objects (one per method):

@Root(name="data")
public class Foo{
    @Element
    public String foo;
    (...)
}
ollo
  • 24,797
  • 14
  • 106
  • 155
mentxugle
  • 83
  • 4

1 Answers1

2

Unfortunately you can't set more than one annotation per field and @Element only supports one name (case sensitive). As an alternative you can deserialize those fields by your own - here's an example how to do this:

@Root(name = "data")
@Convert(FooConverter.class) // Set the converter that's used for serializing / deserializing this class
public class Foo
{
    @Element( name = "foo") // For this solution it doesn't matter what you set here
    public String foo;

    // ...


    /*
     * The converter - Implement the serialization / deserialization here.
     * You don't have to use an inner class here.
     */
    public static class FooConverter implements Converter<Foo>
    {
        @Override
        public Foo read(InputNode node) throws Exception
        {
            Foo f = new Foo();
            InputNode nextNode = node.getNext();

            while( nextNode != null )
            {
                if( nextNode.getName().equalsIgnoreCase("foo") ) // Here you pick-up the node, however it's written
                {
                    f.setFoo(nextNode.getValue());
                }

                nextNode = node.getNext();
            }

            return f;
        }


        @Override
        public void write(OutputNode node, Foo value) throws Exception
        {
            // Not required in this example.
            throw new UnsupportedOperationException("Not supported yet.");
        }

    }
}

Example usage:

String str = "<data><foo>foo value</foo></data>"; // Foo can be written as you like

Serializer ser = new Persister(new AnnotationStrategy()); // Setting the AnnotationStrategy is important!!
Foo f = ser.read(Foo.class, str);

System.out.println(f);

Now it doesn't matter if foo is written as foo or FoO - as long it's a foo.

ollo
  • 24,797
  • 14
  • 106
  • 155
  • Thank you very much! It works! Just one more question... Do I have to serialize via the Converter's read method all the other attributes on Foo, or can I somehow fall back to the default serializing for those? – mentxugle Nov 14 '13 at 19:54
  • Within your converter, you can use a `Serializer` / `Persister` to deserialize a single field; eg. `new Persister().read(FieldClass.class, node)` is possible. You also can set a `Converter` per field! But i guess (I'm not 100% sure), you can't set a converter for a whole class, that manages only a single field. In your case, it would be the best solution to set a Converter only for `foo` field. But since it's name isn't constant, the lookup will use the converter only for those fields with the correct name. – ollo Nov 15 '13 at 14:37
  • Maybe the classes you can set in the `Persister`'s constructor can help you here a bit more. It's a good idea to read their documentation, possible they can provide the behavior you need. – ollo Nov 15 '13 at 14:40