users@jaxb.java.net

Re: Re: Re: Mixing custom/manual marshalling with JAXB

From: Dmitri Colebatch <dim_at_colebatch.com>
Date: Fri, 7 Jul 2006 10:17:58 +1000

Hi Nick,

Sorry - got it slightly wrong. Here you go:

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.List;

@XmlRootElement(namespace = "")
@XmlAccessorType(XmlAccessType.FIELD)
public class Wrapper
{
        @XmlAnyElement(lax = true)
        @XmlJavaTypeAdapter(MyAdapter.class)
        List<String> any;
}

import org.w3c.dom.Element;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class MyAdapter extends XmlAdapter<Element,String>
{
        public Element marshal(String v) throws Exception
        {
                throw new UnsupportedOperationException();
        }

        public String unmarshal(Element v) throws Exception
        {
                return v.toString();
        }
}


import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;

public class PartialUnmarshall
{
        public static void main(String[] args) throws Exception
        {
                Unmarshaller unmarshaller =
JAXBContext.newInstance(Wrapper.class).createUnmarshaller();

                Wrapper wrapper = (Wrapper) unmarshaller.unmarshal(new StringReader(
                        "<wrapper>" +
                                "<pet xmlns:xsi=\"xsi\" xsi:type=\"Cat\" name=\"sooty\"
weight=\"5.5\" guid=\"32l2-k3-43j...\">\n" +
                                " <owner xsi:type=\"Person\" name=\"John\" />\n" +
                                " </pet>" +
                                "</wrapper>"));

                System.out.println("o = " + wrapper);
                for (Object o : wrapper.any)
                {
                        System.out.println("o = " + o + " (" + o.getClass() + ")");
                }

        }
}

the output of that for me is:

o = com.toyota.dim.jaxb.Wrapper_at_1808199
o = [pet: null] (class java.lang.String)

Obviously you would want to use something else instead of String, but
I think the above suits your requirements.

cheers
dim

On 7/6/06, Nick Minutello <nick.minutello_at_gmail.com> wrote:
> Hrm, not sure ... cant see how that would work...
>
> In any case:
> ===
> Exception in thread "main"
> com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of
> IllegalAnnotationExceptions
> javax.xml.bind.JAXBElement does not have a no-arg default constructor.
> this problem is related to the following location:
> at javax.xml.bind.JAXBElement
> at private java.util.Set com.ubs.eqd.data.model.DataGraphImpl.data
> ===
> It doesnt seem to like it.
>
> -Nick
>
> On 7/6/06, Dmitri Colebatch <dim_at_colebatch.com> wrote:
> > I think Billy needs to stop buying so much catfood! (o:
> >
> > Firstly, this is me thinking aloud, none of this is tested, but I
> > think the theory is reasonable.
> >
> > lets for a minute assume that your xml arrives like this:
> >
> > <wrapper-that-is-always-the-same>
> > <pet xsi:type="Cat" name="sooty" weight="5.5" guid="32l2-k3-43j...">
> > <owner xsi:type="Person" name="John" />
> > </pet>
> > </wrapper-that-is-always-the-same>
> >
> > I would imagine that you could do something like this:
> >
> > class Wrapper
> > {
> > @XmlJavaTypeAdapter(Adapter.class);
> > Set<DataObject> stuff;
> > }
> >
> > class Adapter extends XmlAdapter<JAXBElement,DataObject>
> > {
> > JAXBElement marshall(DataObject o) { ... }
> > DataObject unmarshall(JAXBElement e) { ... }
> > }
> >
> > I _think_ that if, in your schema for wrapper, you defined it as
> > containing a sequence of any, that something like the above would
> > work.
> >
> > I imagine the problem is that you don't have the wrapper element....
> > afaik there is a limitation on JAXB2 in that you can only attach
> > XmlJavaTypeAdapter annotations to members, and so you cant do the same
> > thing on a top level element.
> >
> > Having said all that - you may find it simple to just unmarshall into
> > JAXBElement (or indeed an old fashioned JDOM model) and do it some
> > other way.
> >
> > Another approach would be to generate XSLT that turns your XML into
> > something that can be marshalled into JAXB.
> >
> > I think the first approach would be the closest to what you want, but
> > I'm not sure if it suits.
> >
> > cheers
> > dim
> >
> > On 7/6/06, Nick Minutello <nick.minutello_at_gmail.com> wrote:
> > > Hi, thanks Dim.
> > >
> > > I will explain it as briefly and clearly as I can :-)
> > >
> > > (I have had an attempt at doing that previously, here
> > > http://forums.java.net/jive/thread.jspa?threadID=16615&tstart=0 so feel
> > > free to use that as further info)
> > >
> > > The business problem at hand is that we want people to be able to define
> > > some metadata in some storage somewhere (they would create a meta-model
> > > of concepts, their properties & relationships to each other). From this
> > > metamodel, an xml schema representation could be generated dynamically.
> > > We want people to be able to send/receive XML conforming to that xml
> > > schema to/from the server - but we don't want to have to change anything
> > > on the server. The server has a generic data object it works with - and
> > > the xml would get marshalled into and out of that.
> > >
> > > Basically, at a technical level, my problem is this:
> > > I have a bunch of classes that I want to map using JAXB - and I can do
> > > that fine.
> > >
> > > But I have 1 class where the class and the XML are going to be very very
> > > different.
> > > The class is called DataObject which is just a property bag and some
> > > Type information (The type information/metadata tells it what
> > > properties it can have (property name and property type - where one of
> > > the property types might be DataObject)
> > > But basically you can think about it as a Map of Maps.
> > >
> > > The thing is I don't want the DataObject graph to look like a map of
> > > maps when its serialised to XML.
> > > I want it to be readable. I want the xml to look like the domain
> > > concepts defined in the metamodel.
> > >
> > > So, imagine I have the following code to create a small DataObject
> > > graph:
> > >
> > > =====================
> > > // defining the metadata (in my case its stored somewhere centrally)
> > > Type personType = new Type("Person");
> > > personType.addProperty("name", Type.STRING);
> > >
> > > Type petType = new Type("Cat")
> > > petType.addProperty("weight", Type.DECIMAL);
> > > petType.addProperty("name", Type.STRING);
> > > petType.addProperty("owner", personType);
> > >
> > > // now create some instances
> > > DataObject john = new DataObject(personType, new Guid())
> > > john.setProperty("name", "John");
> > >
> > > DataObject sooty= new DataObject(petType, new Guid());
> > > sooty.setProperty("weight", 5.5);
> > > sooty.setProperty("name", "sooty");
> > > sooty.setProperty("owner", john)
> > > =====================
> > >
> > > I want sooty to look like this as XML:
> > >
> > > <pet xsi:type="Cat" name="sooty" weight="5.5" guid="32l2-k3-43j...">
> > > <owner xsi:type="Person" name="John" />
> > > </pet>
> > >
> > > And you can imagine for Fluffy, its like this:
> > > <pet xsi:type="Cat" name="fluffy" weight="15.5" guid="2433-sd9-243...">
> > > <owner xsi:type="Person" name="Billy" />
> > > </pet>
> > >
> > > So, you see the XML looks like it would come from a classes like this:
> > > class Person {
> > > String name;
> > > }
> > > class Cat {
> > > String name;
> > > Double weight;
> > > Person owner;
> > > }
> > >
> > > But these classes don't ever exist.
> > > Effectively, we want to map a bunch of different schema complexType's to
> > > one generic DataObject.
> > > We want people to be able to add a new concept to the metamodel - and
> > > the server handle it with no code change.
> > > The metadata (which would come from some storage) would tell us:
> > > A) what the xml schema would effectively look like (so clients know what
> > > to send/receive)
> > > B) how the server marshals conforming XML to/from our generic DataObject
> > > graph
> > >
> > > So, all the other static classes (like Type & Property, the
> > > ActionCommand's and their Envelopes, etc - a bunch of other stuff) I can
> > > map with JAXB no problem. However, its not clear to me if (let alone
> > > how) I can get JAXB to do the Marshalling/unmarshalling of DataObject
> > > to/from readable XML like you see above.
> > >
> > > What I *don't* want is XML that looks like this:
> > >
> > > <dataobject guid="2433-sd9-243..." doType="Cat" >
> > > <property name="name" xsi:type="xs:string" value="fluffy" />
> > > <property name="weight" xsi:type="xs:double" value="15.5" />
> > > <property name="owner" doType="Person">
> > > <dataobject guid="2433-sd9-243..." doType="Person" >
> > > <property name="name" xsi:type="xs:string" value="Billy" />
> > > </dataobject>
> > > </property>
> > > </dataobject>
> > >
> > > The XML schema in this case would tell me nothing about the domain.
> > >
> > > So, if indeed its not possible to get JAXB to do the marshalling &
> > > unmarshalling, I need to find a way I can get JAXB to delegate the
> > > marshalling/unmarshalling to me whenever it hits a DataObject.
> > >
> > > Can I do this? Does this mechanism exist?
> > > I think I can use a SAX Filter to switch unmarshalling delegation
> > > between JAXB and my own custom SAX DatObject unmarshaller.
> > > I don't see a way I can plug into JAXB's marshalling though.
> > >
> > > I thought I could be cunning and use an XmlJavaTypeAdapter to convert
> > > between DataObject and String - but of course it escapes the String
> > > contents - so marshalling my DataObject into an xml string wasn't the
> > > droid I was looking for...
> > >
> > > Cheers,
> > > -Nick
> > >
> > > On 7/5/06, Dmitri Colebatch <dim_at_colebatch.com> wrote:
> > > > Hi Nick,
> > > >
> > > > Could you explain more about what you're trying to do?
> > > >
> > > > Obviously at compile time you need to know the class structure of what
> > > > you're unmarshalling into.
> > > >
> > > > Are you talking about unmarshalling something like a SOAP envelope
> > > > where the body is any:any? I assume not, but if this is the case then
> > > > as long as the types are in the jaxb context then this works out of
> > > > the box.
> > > >
> > > > If you're talking about unmarshalling into different types of objects
> > > > based on some jvm level context then I don't see why you cant do that
> > > > using XmlJavaTypeAdapter - obviously the return type needs to be
> > > > defined at compile time but you'll never be able to avoid that, but
> > > > that aside you can do whatever you want at runtime.
> > > >
> > > > Could you give a more complete set of requirements please?
> > > >
> > > > cheers
> > > > dim
> > > >
> > > >
> > > > On 7/5/06, Nick Minutello <nick.minutello_at_gmail.com> wrote:
> > > > > I want to use jaxb to marshal&unmarshal my object graph but there are
> > > > > objects within this graph that I need to marshal/unmarshal manually
> > > > > (Its quite complicated marshalling/unmarshalling - it requires data
> > > > > that is only available at runtime to do it).
> > > > >
> > > > > Is there a way I can plug into the marshalling/unmarshalling to do
> > > > > this? If not, can we add it?
> > > > >
> > > > > Question also posted on the forum:
> > > > > http://forums.java.net/jive/thread.jspa?threadID=16648
> > > > >
> > > > > Thanks
> > > > > -Nick
> > > > >
> > > > > ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> > > > > For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> > > > >
> > > > >
> > > >
> > > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> > > > For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> > > >
> > > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> > > For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> > >
> > >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> > For additional commands, e-mail: users-help_at_jaxb.dev.java.net
> >
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jaxb.dev.java.net
> For additional commands, e-mail: users-help_at_jaxb.dev.java.net
>
>