If an XSD has an xs:choice element then it will not be marshalled correctly to a Java object by JAXB.
If your service is not using the wsdlLocation attribute in the @WebService annotation (which we don't normally do) then it will mean the application container (GlassFish / Weblogic) will generate the WSDL and XSD files again for you based on the Java objects when you deploy your service. When this happens the original xs:choice element is lost from the new XSD generated by the container. This will mean any choices submitted in the XML are now no longer validated against the XSD (because no xs:choice element exists!)
http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html
In order to enable xs:choice marshalling to work correctly you need to provide a bindings.xml file. See link below.
XML Schema (customer.xsd)
In this XML schema the choice structure means that after the name element, one of the following elements may occur: address, phone-number, or note.
Default Generated Class
1
xjc -d out -p com.example customer.xsd
If we generate Java classes from our schema using the above command, then we will get a Customer class that looks something like the following (accessors have been omitted to save space). What is surprising here is that JAXB has generated a property for each option in the choice structure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "customer", propOrder = {
"name",
"address",
"phoneNumber",
"note"
})
public class Customer {
protected String name;
protected Address address;
@XmlElement(name = "phone-number")
protected PhoneNumber phoneNumber;
protected String note;
}
Binding File (binding.xml)
We can override the behaviour observed above through the use of a JAXB binding file. In this file we will specify that we want choice structures mapped to a choice property mapped with @XmlElements.
1
2
3
4
5
Generated Class (using Binding File)
1
xjc -d out -p com.example -b binding.xml customer.xsd
Now if we generate Java classes from our schema using the above command (which specifies the binding file), we will get a Customer class that looks something like the following (again accessors have been omitted to save space). We see that we have one property that corresponds to the choice structure that is annotated with @XmlElements.
package com.example;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "customer", propOrder = {
"name",
"addressOrPhoneNumberOrNote"
})
public class Customer {
protected String name;
@XmlElements({
@XmlElement(name="phone-number", type=PhoneNumber.class),
@XmlElement(name="address", type=Address.class),
@XmlElement(name="note", type=String.class)
})
protected Object addressOrPhoneNumberOrNote;
}
No comments:
Post a Comment