I'm trying to get MOXy or JAXB RI to marshal null collections to an xsi:nil element like so:
<element xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
The use case is:
- Axis2 SOAP endpoint I have no control of
- I'm on the client side
- Endpoint expects xsi:nil elements for null collections but does not allow them to be wrapped (using @XmlElementWrapper) which would generate the required xsi:nil element for the wrapping element.
- I can only use JAX-WS RI as of JDK 6 r4+ or the latest Metro implementation.
- I can use the JAXB RI or the MOXy implementation.
- I'm on EclipseLink 2.5.1
- The bound types are generated from the service WSDL by wsimport at build time. So any solution not requiring post-processing the generated sources for annotation modification would be preferable.
I'm aware that JAXB RI as of 2.2.6 probably has no way of doing that, but maybe I missed something. I checked the sources and it basically says, non-parametrized: "If it's a List and if it's null, only ever output anything if @XmlElementWrapper is present on field". But unfortunately this is not a solution for this case.
I tried MOXy and the use of its @XmlNullPolicy annotation but it seems to have no effect on collection properties. Is there another way to make MOXy output xsi:nil elements for emtpty collections?
I created a test case to give an example of what happens. First and second are the actual result and the result I need. Third is the jaxb.properties file required to enable MOXy for the actual use case in the fourth code block.
This is what I get when executing the test case at the bottom:
<?xml version="1.0" encoding="UTF-8"?>
<model>
<nonCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<nonCollectionEmptyNode/>
<wrappedNullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</model>
This is what I need:
<?xml version="1.0" encoding="UTF-8"?>
<model>
<nonCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<nonCollectionEmptyNode/>
<nullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<wrappedNullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</model>
jaxb.properties
This file need to be in the same package as the test case below otherwise MOXy will not be used.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Test case:
package test;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlMarshalNullRepresentation;
import org.eclipse.persistence.oxm.annotations.XmlNullPolicy;
/**
* jaxb.properties containing string:
* "javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory"
* needs to be in the same package as this class to enable MOXy.
*/
public class XmlNullPolicyTest
{
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
private static class Model
{
/**
* Outputs xsi:nil elements when using JAXB RI or MOXy.
*/
@XmlElement(required = true, nillable = true)
protected String nonCollection;
/**
* This is here to test if the EclipseLink implementation is actually used.
* To enable MOXy JAXB impl put jaxb.properties containing text
* "javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory"
* in the same package as this class.
*
* Using the RI it outputs:
* <nonCollectionEmptyNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
*
* And with MOXy, because it processes @XmlNullPolicy:
* <nonCollectionEmptyNode/>
*/
@XmlElement(required = true, nillable = true)
@XmlNullPolicy(
nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE
)
protected String nonCollectionEmptyNode;
/**
* Need this one to work. Should marshal to:
* <nullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
* ...if possible.
*/
@XmlElement(required = true, nillable = true)
@XmlNullPolicy(
nullRepresentationForXml = XmlMarshalNullRepresentation.XSI_NIL,
xsiNilRepresentsNull = true
)
private List<String> nullCollection = null;
/**
* Cannot use this one, since it the service expects elements unwrapped.
* Works though as long as the list is actually null.
*/
@XmlElement(required = true, nillable = true)
@XmlElementWrapper(nillable = true)
private List<String> wrappedNullCollection = null;
}
public static void main(String[] args)
throws JAXBException
{
final JAXBContext jaxbContext =
JAXBContext.newInstance(Model.class);
final Marshaller marshaller =
jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(new Model(), System.out);
}
}
I appreciate any help.
Thank you for you attention!
Best regards,
Christian