users@jaxb.java.net

Re: Error marshalling JAXB object

From: Wolfgang Laun <wolfgang.laun_at_gmail.com>
Date: Sat, 8 Aug 2009 16:44:37 +0200

This is the essential part of the class MyBean containing the Map:

    @XmlElement( name = "adaptedMap" )
    @XmlJavaTypeAdapter(MyHashMapAdapter.class)
    protected Map<String,ArrayList<String>> valueMapList = null;

    public Map<String, ArrayList<String>> getValueMapList() {
        if( valueMapList == null ) valueMapList = new HashMap<String,
ArrayList<String>>();
        return valueMapList;
    }

To construct a type (ValueType) that JAXB can handle "out of the box",
imagine the Map as a list of Map.Entry elements, which, in turn, has a
String key and a List<String> value. Write a class representing this
structure:

@XmlAccessorType( XmlAccessType.NONE )
public class ListKeyListType {
    private List<KeyListType> listKeyList;
    public ListKeyListType(){
    }
    @XmlElement( name = "mapEntry" )
    public List<KeyListType> getListKeyList() {
        if( listKeyList == null ) listKeyList = new
ArrayList<KeyListType>();
        return listKeyList;
    }

    @XmlAccessorType( XmlAccessType.NONE )
    public static class KeyListType {
        @XmlElement
        private String key;
        @XmlElement( name = "listEntry" )
        private List<String> list;

        public KeyListType(){
        }
         // getters, setters...
    }
}

Now the XmlAdapter subclass has to convert values between a ListKeyListType
and a Map<String,List<String>>. Simply iterate over the list (or the map)
and create map (or list) entries.

public class MyHashMapAdapter
    extends XmlAdapter<ListKeyListType, Map<String,List<String>>> {

    @Override
    public Map<String,List<String>> unmarshal( ListKeyListType value ) {
        Map<String,List<String>> res = new HashMap<String,List<String>>();
        for( ListKeyListType.KeyListType lkl: value.getListKeyList() ){
            res.put( lkl.getKey(), lkl.getList() );
        }
        return res;
    }

    @Override
    public ListKeyListType marshal( Map<String,List<String>> value ) {
        ListKeyListType res = new ListKeyListType();
        List<ListKeyListType.KeyListType> lkl = res.getListKeyList();

        for( Map.Entry<String,List<String>> e: value.entrySet() ){
        ListKeyListType.KeyListType kl = new ListKeyListType.KeyListType();
            kl.setKey( e.getKey() );
            kl.setList( e.getValue() );
            lkl.add( kl );
        }
        return res;
    }
}

I have added names to @XmlElement, so as to have better tags in the
resulting XML, e.g.:

<myBean>
    <adaptedMap>
        <mapEntry>
            <key>key2</key>
            <listEntry>ela</listEntry>
            <listEntry>elb</listEntry>
        </mapEntry>
        <mapEntry>
            <key>key1</key>
            <listEntry>el1</listEntry>
            <listEntry>el2</listEntry>
        </mapEntry>
    </adaptedMap>
    <name>BakedBean</name>
</myBean>

Variations are possible. You might choose to represent the key as an
attribute, simply by using the @XmlAttribute annotation. You might go for a
totally different representation, e.g., a flat list of <key> and <listEntry>
elements, where the order determines the grouping into map entries, which
would require different code for the ValueType and the XmlAdapter subclass.
And so on.

-W


On Sat, Aug 8, 2009 at 5:54 AM, swtking <rajkal23_at_yahoo.com> wrote:

>
> My bad gave wrong example...
>
> Yes I am looking similar to this.. Can you tell me what part of my code
> should be changed in order to achieve this?
>
> <myBean>
> <entry>
> <key>flower</key><valueList>rose lily</valueList>
> </entry>
> <entry>
> <key>fruit</key><valueList>apple orange</valueList>
> </entry>
> </myBean>
>
>
>
> Wolfgang Laun-2 wrote:
> >
> > On Fri, Aug 7, 2009 at 9:23 PM, swtking <rajkal23_at_yahoo.com> wrote:
> >
> >>
> >> Thanks for your response. Made changes to MyHashMapAdapter.java the
> >> format
> >> I
> >> needed but still no luck.
> >>
> >> I am trying to get output in this format.
> >>
> >> <xml>
> >> <abc>
> >> <123></123>
> >> <345></345>
> >> </abc>
> >> <def>
> >> <789></789>
> >> </def>
> >> </xml>
> >>
> >
> > You won't be able to get anywhere close to this, for several reasons:
> > - tags can't start with a digit
> > - values can't be tags
> > - unless you override in XmlElement etc., tags will be derived from field
> > names
> >
> > Maybe like this:
> >
> > <myBean>
> > <entry>
> > <key>flower</key><valueList>rose lily</valueList>
> > </entry>
> > <entry>
> > <key>fruit</key><valueList>apple orange</valueList>
> > </entry>
> > </myBean>
> >
> > -W
> >
> >
> >>
> >>
> >> MyBean.java
> >>
> >> private Map<String,List<String>> valueMapList=null;
> >>
> >> @XmlJavaTypeAdapter(MyHashMapAdapter.class)
> >> @XmlElement
> >> public Map<String, List<String>> getValueMapList() {
> >> return valueMapList;
> >> }
> >>
> >> public void setValueMapList(Map<String, List<String>>
> valueMapList)
> >> {
> >> this.valueMapList = valueMapList;
> >> }
> >>
> >>
> >> MyHashMapAdapter.java
> >>
> >> public class MyHashMapAdapter extends
> >> XmlAdapter<HashMap<String,List<String>>, Map<String,List<String>>> {
> >>
> >> @Override
> >> public HashMap<String,List<String>> unmarshal( String[] value )
> {
> >>
> >> HashMap<String,List<String>> m = new HashMap<String,List<String>>();
> >> return m;
> >> }
> >>
> >>
> >> @Override
> >> public String[] marshal(List<String> arg0) throws Exception {
> >> String[] s = (String[]) arg0.toArray();
> >> return s;
> >> }
> >>
> >> }
> >>
> >>
> >>
> >> Wolfgang Laun-2 wrote:
> >> >
> >> > The adapter converts between String[] and List<String> but the element
> >> to
> >> > which the adapter is attached to is a Map<?,?>.
> >> >
> >> > You could attach an adapter to MyBean, to convert between its field
> >> > valueMapList and whatever. You'll have to design a class that's
> capable
> >> of
> >> > storing the same information as MyBean but can be handled by JAXB and
> >> is
> >> > structured according to the XML structure you want.
> >> >
> >> > -W
> >> >
> >> >
> >> > On Thu, Aug 6, 2009 at 9:16 PM, swtking <rajkal23_at_yahoo.com> wrote:
> >> >
> >> >>
> >> >> Could anyone tell me what I am doing wrong.
> >> >>
> >> >> Trying to marshall a complex map (Map<String,List<String>>)
> >> >>
> >> >> MyBean.java
> >> >>
> >> >> private Map<String,List<String>> valueMapList=null;
> >> >>
> >> >> @XmlJavaTypeAdapter(MyHashMapAdapter.class)
> >> >> @XmlElement
> >> >> public Map<String, List<String>> getValueMapList() {
> >> >> return valueMapList;
> >> >> }
> >> >>
> >> >> public void setValueMapList(Map<String, List<String>>
> >> >> valueMapList)
> >> >> {
> >> >> this.valueMapList = valueMapList;
> >> >> }
> >> >>
> >> >>
> >> >> MyHashMapAdapter.java
> >> >>
> >> >> public class MyHashMapAdapter extends XmlAdapter<String[],
> >> List<String>>
> >> >> {
> >> >>
> >> >> public List<String> unmarshal( String[] value ) {
> >> >> List<String> r = new ArrayList<String>();
> >> >> for( String s : value )
> >> >> r.add(s);
> >> >> return r;
> >> >> }
> >> >>
> >> >> public String[] unmarshal( List<String> value ) {
> >> >> return value.toArray(new String[value.size()]);
> >> >> }
> >> >>
> >> >> @Override
> >> >> public String[] marshal(List<String> arg0) throws Exception {
> >> >> String[] s = (String[]) arg0.toArray();
> >> >> return s;
> >> >> }
> >> >>
> >> >> }
> >> >>
> >> >>
> >> >> This is my error
> >> >>
> >> >> java.io.IOException: Error marshalling JAXB object of type "class
> >> >> com.MyBean".
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:145)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:254)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:578)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:502)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:493)
> >> >> Truncated. see log file for complete stacktrace
> >> >> com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 3 counts of
> >> >> IllegalAnnotationExceptions
> >> >> Adapter com.MyHashMapAdapter is not applicable to the field type
> >> >> java.util.Map<java.lang.String, java.util.List<java.lang.String>>.
> >> >> this problem is related to the following location:
> >> >> at
> >> >> @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=class
> >> >> javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter$DEFAULT,
> >> >> value=class
> >> >> com.MyHashMapAdapter)
> >> >> at public java.util.Map com.MyBean.getValueMapList()
> >> >> at com.MyBean
> >> >> java.util.Map is an interface, and JAXB can't handle interfaces.
> >> >> this problem is related to the following location:
> >> >> at java.util.Map
> >> >> at public java.util.Map com.MyBean.getValueMapList()
> >> >> at com.MyBean
> >> >> java.util.Map does not have a no-arg default constructor.
> >> >> this problem is related to the following location:
> >> >> at java.util.Map
> >> >> at public java.util.Map com.MyBean.getValueMapList()
> >> >> at com.MyBean
> >> >>
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:447)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:288)
> >> >> at
> >> >>
> >> >>
> >>
> com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1111)
> >> >> at
> >> >>
> >>
> com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
> >> >> Truncated. see log file for complete stacktrace
> >> >>
> >> >>
> >> >> --
> >> >> View this message in context:
> >> >>
> >>
> http://www.nabble.com/Error-marshalling-JAXB-object-tp24852727p24852727.html
> >> >> Sent from the java.net - jaxb users mailing list archive at
> >> Nabble.com.
> >> >>
> >> >>
> >> >> ---------------------------------------------------------------------
> >> >> To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> >> >> For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> >> >>
> >> >>
> >> >
> >> >
> >>
> >> --
> >> View this message in context:
> >>
> http://www.nabble.com/Error-marshalling-JAXB-object-tp24852727p24870320.html
> >> Sent from the java.net - jaxb users mailing list archive at Nabble.com.
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> >> For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> >>
> >>
> >
> >
>
> --
> View this message in context:
> http://www.nabble.com/Error-marshalling-JAXB-object-tp24852727p24874694.html
> Sent from the java.net - jaxb users mailing list archive at Nabble.com.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> For additional commands, e-mail: users-help_at_jaxb.dev.java.net
>
>