I have re-formatted the question to hopefully make my intentions clearer.
Architecture
I\'m writing some web services that I will be publishing
As I understand you Ben the following XSD:
<xs:element name="myElement" type="xs:string" nillable="true" minOccurs="0" />
Should result in:
@XmlElementRef(name = "myElement", namespace = "/mynamespace", type = JAXBElement.class, required = false)
protected JAXBElement<String> myElement;
Right?
But for default JAXB implementation it is not the case. Looks like a bug in JAXB. I didn't find it in JAXB issue tracker. required
attribute was introduced to @XmlElementRef
in JAXB 2.2 in around 2009 but apparently no one created issue for this problem.
required
attribute cannot be changed using Binding Customizations.
In this situation you can:
@XmlElementRef
annotation. It is not that difficult. More information here.required = false
is generated using MOXy JAXB compiler)No matter which option you choose please raise issue in JAXB issue tracker so that the problem will be fixed.
EDIT:
To show that creating plugin is easy I created one. You can find it in my github repository. Feel free to use/copy/modify at will. I don't give guarantee that it works in 100% but for simple cases works like a charm.
EDIT2:
If schema generated based on java objects and JAXB annotations does not match your interface then you can use @WebService.wsdlLocation
to point to your original, correct WSDL and XSD files.
EDIT3:
It's weird that nil
is ignored by JAXB in your case. I ran a test using JAXB 2.2.6 and 2.2.7 and nil
is correctly recognized:
JAXBContext context = JAXBContext.newInstance(SomeElement.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns2:someElement xmlns:ns2=\"http://www.example.org/example/\"><myElement xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/></ns2:someElement>";
SomeElement someElement = (SomeElement) unmarshaller
.unmarshal(new StringReader(xml));
assertThat(someElement.getMyElement().isNil(), is(true));
Could you check whether you correctly set nil attribute, e.g.:
<myElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
If it is correct please try to run the test with your class.
You can customise the binding by
<jaxb:globalBindings generateElementProperty="false" />
As documented in Customized Binding , for the same exact case you are asking about.
I'm using custom binding with maven plugin org.jvnet.jaxb2.maven2:maven-jaxb2-plugin
For
@XmlElementRef(name="foo", required=false)
protected JAXBElement<String> foo;
An absent node in the document will correspond to this field being null. An XML element present in the document with xsi:nil="true"
will correspond to the value being an instance of JAXBElement
with a value of null
.
You can also provide an XML schema instead of having JAXB generate one using the location
property on the package level @XmlSchema
annotation.
@XmlSchema(
...
location="http://www.example.com/schema/root.xsd")
package forum19665550;
import javax.xml.bind.annotation.XmlSchema;
Root
This is an object with two fields that can represent optional and nillable data.
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElementRef(name="foo", required=false)
protected JAXBElement<String> foo;
@XmlElementRef(name="bar", required=false)
protected JAXBElement<String> bar;
}
ObjectFactory
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="foo")
public JAXBElement<String> createFoo(String foo) {
return new JAXBElement<String>(new QName("foo"), String.class, foo);
}
@XmlElementDecl(name="bar")
public JAXBElement<String> createBar(String bar) {
return new JAXBElement<String>(new QName("bar"), String.class, bar);
}
}
Demo
The demo code below will investigate the differences in the values for foo
and bar
. You can use the JAXBIntrospector
class to get the real value for an instance of JAXBElement
. There is a bug in EclipseLink JAXB (MOXy) related to unmarshalling an instance of JAXBElement
wrapping a null value (see: http://bugs.eclipse.org/420746).
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum19665550/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
System.out.println("foo was set: " + (root.foo != null));
System.out.println("bar was set: " + (root.bar != null));
System.out.println("foo value: " + root.foo);
System.out.println("bar value: " + root.bar);
System.out.println("foo unwrapped value: " + JAXBIntrospector.getValue(root.foo));
System.out.println("bar unwrapped value: " + JAXBIntrospector.getValue(root.bar));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml/Output
In the resulting output we see that we can differentiate between an element being absent from the document and an element with `xsi:nil="true" and still have the resulting value be null.
foo was set: false
bar was set: true
foo value: null
bar value: javax.xml.bind.JAXBElement@4af42ea0
foo unwrapped value: null
bar unwrapped value: null
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
GenerateSchema
Below is some JAXB code that will generate an XML Schema from the annotated model.
import java.io.IOException;
import javax.xml.bind.*;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
public class GenerateSchema {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
jc.generateSchema(new SchemaOutputResolver() {
@Override
public Result createOutput(String namespaceUri,
String suggestedFileName) throws IOException {
StreamResult result = new StreamResult(System.out);
result.setSystemId(suggestedFileName);
return result;
}
});
}
}
Output
Here is the resulting XML Schema. You are correct that it doesn't indicate that the foo
and bar
elements are nillable.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bar" type="xs:string"/>
<xs:element name="foo" type="xs:string"/>
<xs:element name="root" type="root"/>
<xs:complexType name="root">
<xs:sequence>
<xs:element ref="foo" minOccurs="0"/>
<xs:element ref="bar" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Instead of having JAXB derive an XML Schema from your model, you can point to your existing one that will contain more information.
package-info
This is done by specifying the location
property on the package level @XmlSchema
annotation.
@XmlSchema(
...
location="http://www.example.com/schema/root.xsd")
package forum19665550;
import javax.xml.bind.annotation.XmlSchema;