You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@tuscany.apache.org by Padraig Myers <Pa...@channeladvisor.com> on 2011/03/31 19:38:01 UTC

JaxB Unmarshaller not working properly for xsi:nil

Hi,

Need help in regards to a problem with how Tuscany handles xsi:nil when
unmarshalling request attributes.

If the request contains a complex object, for example

<assignImageToUser xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <imageId>0</imageId>

  <userId>2</userId>

  <privacy>1</privacy>

  <privacyList xsi:nil="true"></privacyList>

</assignImageToUser>

 

It transforms each of the objects adding xsi:type if it is a complex
object, such that privacyList in the above example becomes:

<privacyList
xmlns:_typens_="http://business.management.image.company.com/"
xsi:nil="true" xsi:type="_typens_:privacyListDTO"></privacyList>

 

However because of a fix put into the JRE in
"com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.selectLo
ader(UnmarshallingContext.State state, TagName ea)" it creates the
object if the number of attributes is more than 1.

The offending piece of code is:

boolean hasOtherAttributes = (ea.atts.getLength() - 1) > 0;

      // see issues 6759703 and 565 - need to preserve attributes even
if the element is nil; only when the type is stored in JAXBElement

      if (!(hasOtherAttributes && (state.prev.target instanceof
JAXBElement))) {

          return Discarder.INSTANCE;

      }

 

What the above code means is that when the assignImageToUser method is
called it will construct the privacy list argument instead of passing it
in as null.

 

Is there some way of creating our own unmarshaller that wraps the
default unmarshaller, so that we can remove the xsi:type before it calls
XsiNilLoader.selectLoader()?

The xsi:type is no longer needed at this stage because the type object
has already been constructed.

 

Thanks, 

Padraig

 

 

 


RE: JaxB Unmarshaller not working properly for xsi:nil

Posted by Padraig Myers <Pa...@channeladvisor.com>.
Hi Scott,
Yes, it's the unwrap-then-transform to JAXB that is the problem.
You are adding two attributes, however once you are finished with them
they should be removed before the call to unmarshaller.unmarshal(reader,
type) in OMElement2JAXB.transform().

The two attributes that you are adding to the node are causing
XsiNilLoader (as detailed in the original mail) to return
StructureLoader instead of Discarder.INSTANCE.

This means that when the webservice method is called it will get an
empty object instead of null.
This renders any check for (arg == null) in the method to function
incorrectly (as the argument that was passed with 'XSI:null=true' if not
null).

Padraig



-----Original Message-----
From: scottkurz@gmail.com [mailto:scottkurz@gmail.com] On Behalf Of
Scott Kurz
Sent: 31 March 2011 20:37
To: user@tuscany.apache.org
Subject: Re: JaxB Unmarshaller not working properly for xsi:nil

Hi Padraig,


On Thu, Mar 31, 2011 at 1:38 PM, Padraig Myers
<Pa...@channeladvisor.com> wrote:

> It transforms each of the objects adding xsi:type if it is a complex
object,
> such that privacyList in the above example becomes:
>
> <privacyList
xmlns:_typens_="http://business.management.image.company.com/"
> xsi:nil="true" xsi:type="_typens_:privacyListDTO"></privacyList>


Just want to make sure I'm following.   It sounds like you're talking
about the path in which we unwrap-then-transform to JAXB, right?
I know in this path the OMElementWrapperHandler will add the xsi:type
to each wrapper child to facilitate the transform from OMElement child
to JAXB child.

Does that sound like what you are talking about?

If so, one thing worth considering is that you should be able to
bypass this path by using a schema-valid payload, if this is an option
for you.    With a schema-valid payload, we will typically do a
wrapper->wrapper transform from XML->JAXB, whereas with a non-valid
payload we will go down this child->child transform path.

If that's not relevant or if somehow the problem still exists, have
you looked at using  @XmlJavaTypeAdapter
to customize unmarshalling.   I don't have any particularly good doc
to point to, but there is some info out there on the subject, and
there's always the Java doc.

Hope that helps,
Scott

Re: JaxB Unmarshaller not working properly for xsi:nil

Posted by Scott Kurz <sk...@gmail.com>.
Padraig,

I think I see what you're saying.  It seems to me the issue is better
illustrated if we tweak your test case XML to look like:

    private static final String XMLWithNil =
        "<ns0:root xmlns:ns0=\"http://ns0\"
xmlns:ns2=\"http://www.example.com/IPO\">" + "<ns1:next
xmlns:ns1=\"http://ns1\">"
            + "<ns2:purchaseOrder
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:nil=\"true\" xsi:type=\"ns2:PurchaseOrderType\"/>"
           + "</ns1:next>"
          + "</ns0:root>";

If we unmarshal this to JAXB, we get an "empty" PurchaseOrderType
whereas if the xsi:type is not present, e.g."

    private static final String XMLWithNil =
        "<ns0:root xmlns:ns0=\"http://ns0\"
xmlns:ns2=\"http://www.example.com/IPO\">" + "<ns1:next
xmlns:ns1=\"http://ns1\">"
             + "<ns2:purchaseOrder
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:nil=\"true\" />"
           + "</ns1:next>"
          + "</ns0:root>";

then we get a 'null'.

This test, then, simulates the way that OMElementWrapperHandler would
unwrap a wrapper element then add xsi:type to each wrapper child.

This seems to be a better test than the one you suggested since your
xsi:type was not added to the <purchaseOrder> element being
unmarshalled (as a top-level element), but rather to its child,
<shipTo>.    So the fact that this child element was not defined with
nillable="true" in the schema means that you're not giving JAXB a
schema-valid payload, in which case I would think we're going to have
to live with the implementation details and will have a hard time
adjusting in Tuscany.

So.. assuming I've understood the issue correctly, I would start by
recommending that you open a JIRA to track the issue.

I could imagine possibly making a change to the Tuscany runtime to not
add xsi:type if xsi:nil="true", but would like to open the issue for
comment.  At some point we should see what, if anything, the JAXB spec
says for a usecase like this.

Thanks,
Scott

RE: JaxB Unmarshaller not working properly for xsi:nil

Posted by Padraig Myers <Pa...@channeladvisor.com>.
I have attached an update to the databinding-jaxb-axiom test cases that
demonstrates the problem:
The test file in question is in
modules\databinding-jaxb-axiom\src\test\java\org\apache\tuscany\databind
ing\jaxb\axiom\OMElement2JAXBTestCase.java

Padraig


-----Original Message-----
From: scottkurz@gmail.com [mailto:scottkurz@gmail.com] On Behalf Of
Scott Kurz
Sent: 31 March 2011 20:37
To: user@tuscany.apache.org
Subject: Re: JaxB Unmarshaller not working properly for xsi:nil

Hi Padraig,


On Thu, Mar 31, 2011 at 1:38 PM, Padraig Myers
<Pa...@channeladvisor.com> wrote:

> It transforms each of the objects adding xsi:type if it is a complex
object,
> such that privacyList in the above example becomes:
>
> <privacyList
xmlns:_typens_="http://business.management.image.company.com/"
> xsi:nil="true" xsi:type="_typens_:privacyListDTO"></privacyList>


Just want to make sure I'm following.   It sounds like you're talking
about the path in which we unwrap-then-transform to JAXB, right?
I know in this path the OMElementWrapperHandler will add the xsi:type
to each wrapper child to facilitate the transform from OMElement child
to JAXB child.

Does that sound like what you are talking about?

If so, one thing worth considering is that you should be able to
bypass this path by using a schema-valid payload, if this is an option
for you.    With a schema-valid payload, we will typically do a
wrapper->wrapper transform from XML->JAXB, whereas with a non-valid
payload we will go down this child->child transform path.

If that's not relevant or if somehow the problem still exists, have
you looked at using  @XmlJavaTypeAdapter
to customize unmarshalling.   I don't have any particularly good doc
to point to, but there is some info out there on the subject, and
there's always the Java doc.

Hope that helps,
Scott

Re: JaxB Unmarshaller not working properly for xsi:nil

Posted by Scott Kurz <sk...@gmail.com>.
Hi Padraig,


On Thu, Mar 31, 2011 at 1:38 PM, Padraig Myers
<Pa...@channeladvisor.com> wrote:

> It transforms each of the objects adding xsi:type if it is a complex object,
> such that privacyList in the above example becomes:
>
> <privacyList xmlns:_typens_="http://business.management.image.company.com/"
> xsi:nil="true" xsi:type="_typens_:privacyListDTO"></privacyList>


Just want to make sure I'm following.   It sounds like you're talking
about the path in which we unwrap-then-transform to JAXB, right?
I know in this path the OMElementWrapperHandler will add the xsi:type
to each wrapper child to facilitate the transform from OMElement child
to JAXB child.

Does that sound like what you are talking about?

If so, one thing worth considering is that you should be able to
bypass this path by using a schema-valid payload, if this is an option
for you.    With a schema-valid payload, we will typically do a
wrapper->wrapper transform from XML->JAXB, whereas with a non-valid
payload we will go down this child->child transform path.

If that's not relevant or if somehow the problem still exists, have
you looked at using  @XmlJavaTypeAdapter
to customize unmarshalling.   I don't have any particularly good doc
to point to, but there is some info out there on the subject, and
there's always the Java doc.

Hope that helps,
Scott