JAXB: How should I marshal complex nested data structures?

后端 未结 6 1202
无人及你
无人及你 2020-11-27 02:27

I have several complex data structures like

Map< A, Set< B > >
Set< Map< A, B > >
Set< Map< A, Set< B > > >
Map<         


        
6条回答
  •  鱼传尺愫
    2020-11-27 03:00

    I've solved the problem without XmlAdapter's.

    I've written JAXB-annotated objects for Map, Map.Entry and Collection.
    The main idea is inside the method xmlizeNestedStructure(...):

    Take a look at the code:

    public final class Adapters {
    
    private Adapters() {
    }
    
    public static Class[] getXmlClasses() {
        return new Class[]{
                    XMap.class, XEntry.class, XCollection.class, XCount.class
                };
    }
    
    public static Object xmlizeNestedStructure(Object input) {
        if (input instanceof Map) {
            return xmlizeNestedMap((Map) input);
        }
        if (input instanceof Collection) {
            return xmlizeNestedCollection((Collection) input);
        }
    
        return input; // non-special object, return as is
    }
    
    public static XMap xmlizeNestedMap(Map input) {
        XMap ret = new XMap();
    
        for (Map.Entry e : input.entrySet()) {
            ret.add(xmlizeNestedStructure(e.getKey()),
                    xmlizeNestedStructure(e.getValue()));
        }
    
        return ret;
    }
    
    public static XCollection xmlizeNestedCollection(Collection input) {
        XCollection ret = new XCollection();
    
        for (Object entry : input) {
            ret.add(xmlizeNestedStructure(entry));
        }
    
        return ret;
    }
    
    @XmlType
    @XmlRootElement
    public final static class XMap {
    
        @XmlElementWrapper(name = "map")
        @XmlElement(name = "entry")
        private List> list = new LinkedList>();
    
        public XMap() {
        }
    
        public void add(K key, V value) {
            list.add(new XEntry(key, value));
        }
    
    }
    
    @XmlType
    @XmlRootElement
    public final static class XEntry {
    
        @XmlElement
        private K key;
    
        @XmlElement
        private V value;
    
        private XEntry() {
        }
    
        public XEntry(K key, V value) {
            this.key = key;
            this.value = value;
        }
    
    }
    
    @XmlType
    @XmlRootElement
    public final static class XCollection {
    
        @XmlElementWrapper(name = "list")
        @XmlElement(name = "entry")
        private List list = new LinkedList();
    
        public XCollection() {
        }
    
        public void add(V obj) {
            list.add(obj);
        }
    
    }
    
    }
    
    
    

    It works!

    Let's look at a demo output:

    
        
            
                
                    1
                    a
                
                
                    
                        a1
                        a2
                        a3
                    
                
            
            
                
                    2
                    b
                
                
                    
                        b1
                        b3
                        b2
                    
                
            
            
                
                    3
                    c
                
                
                    
                        c1
                        c2
                        c3
                    
                
            
        
    
    

    Sorry, the demo output uses also a data structure called "count" which is not mentioned in the Adapter's source code.

    BTW: does anyone know how to remove all these annoying and (in my case) unnecessary xsi:type attributes?

    提交回复
    热议问题