I am facing issues marshalling and unmarshalling collections using MOXy. Collection may hold elements of any type. In the test case below I am trying to marshal and then unmarshall colection of Strings.

Test generates following output:

Going with type: APPLICATION_XML
Original XmlCollection: [one, two, three]
Marshaled as application/xml: <?xml version="1.0" encoding="UTF-8"?><collection>onetwothree</collection>

Unmarshaled XmlCollection: []
Going with type: APPLICATION_JSON
Original XmlCollection: [one, two, three]
Marshaled as application/json: {"value":["one","two","three"]}
Unmarshaled XmlCollection: []

In the XML case I would expect collection elements to be serialized as nested list xml elements holding values, but it is not so.

In the case of JSON genereated code looks good but I would expect object to get unmarshalled properly, which didn't happen.

When I run test with Collection of SimpleObject (uncomment lines marked as Simple object) everything works like a sharm and output produced is following:

Going with type: APPLICATION_XML
Original XmlCollection: [stringField='one', stringField='two', stringField='three']
Marshaled as application/xml: <?xml version="1.0" encoding="UTF-8"?><collection><simpleObject><stringField>one</stringField></simpleObject><simpleObject><stringField>two</stringField></simpleObject><simpleObject><stringField>three</stringField></simpleObject></collection>
Unmarshaled XmlCollection: [stringField='one', stringField='two', stringField='three']
Going with type: APPLICATION_JSON
Original XmlCollection: [stringField='one', stringField='two', stringField='three']
Marshaled as application/json: {"simpleObject":[{"stringField":"one"},{"stringField":"two"},{"stringField":"three"}]}
Unmarshaled XmlCollection: [stringField='one', stringField='two', stringField='three']

Appreciate any clue why it happens and how this mapping must be done properly.

Test case:

public class TestCase {
    // Element name holding value of primitive types
    public static final String VALUE_ELEMENT = "value";
    // Attribute prefix in JSON
    public static final String ATTRIBUTE_PREFIX = "@";

    public static void main(String... args) {
        try {
            for (MediaType type : new MediaType[]{MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) {
                System.out.println("Going with type: " + type);
                JAXBContext context = (JAXBContext) JAXBContextFactory.createContext(
                    new Class[]{
                        XmlCollection.class,
//  Simple Object                          SimpleObject.class,
                    },
                    Collections.emptyMap());

                Marshaller marshaller = context.createMarshaller();
                marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, type);
                marshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
                marshaller.setProperty(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX);
                marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT);
                marshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);

                XmlCollection original = new XmlCollection(Arrays.asList("one", "two", "three"));
// Simple object                XmlCollection original = new XmlCollection(Arrays.asList(new SimpleObject("one"), new SimpleObject("two"), new SimpleObject("three")));

                System.out.println("Original " + original.toString());

                StreamResult result = new StreamResult(new StringWriter());
                marshaller.marshal(original, result);
                String generated = result.getWriter().toString();
                System.out.println("Marshaled as " + type.getMediaType() + ": " + generated);

                Unmarshaller unmarshaller = context.createUnmarshaller();
                unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, type);
                unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
                unmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX);
                unmarshaller.setProperty(UnmarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT);
                unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);


                XmlCollection unmarshaled = unmarshaller.unmarshal(new StreamSource(new StringReader(generated)), XmlCollection.class).getValue();
                System.out.println("Unmarshaled " + unmarshaled.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @XmlRootElement(name = "collection")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class XmlCollection<T> {
        @XmlAnyElement(lax = true)
        private Collection collection = new ArrayList();

        public XmlCollection() {
        }

        public XmlCollection(Collection<T> collection) {
            this.collection.addAll(collection);
        }

        public Collection<T> getCollection() {
            return collection;
        }

        @Override
        public String toString() {
            return "XmlCollection: " + collection;
        }
    }

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static final class SimpleObject{
        @XmlElement
        public String stringField;
        public SimpleObject(){}

        public SimpleObject(String stringField){
            this.stringField = stringField;
        }

        public String getStringField() {
            return stringField;
        }

        public void setStringField(String stringField) {
            this.stringField = stringField;
        }    

       @Override
       public String toString() {
            return "stringField='" + stringField + '\'';
       }
   }
}
0

There are 0 answers