Java – JAXB converts @ xmlelementrefs and @ xmlelements to XS: choice
I have four classes The person class, and the phone and address classes are used to extend its abstract contactinformation
@XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class Person { @XmlElement(required = true,nillable = false) private String first; @XmlElement(required = true,nillable = false) private String last; @XmlElementWrapper(name = "contacts") @XmlElementRefs({ @XmlElementRef(name = "phone",type = Phone.class,required = true),@XmlElementRef(name = "address",type = Address.class,required = true) }) private final List<ContactInfomation> contacts = new ArrayList<>(); }
Contactinformation is used as a container only:
public abstract class ContactInfomation { /* empty class */ }
Telephone:
@XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class Phone extends ContactInfomation { @XmlElement(required = true,nillable = false) private String number; }
And address classes:
@XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class Address extends ContactInfomation { @XmlElement(required = true,nillable = false) private String country; @XmlElement(required = true,nillable = false) private String city; }
The problem is that when I change @ xmlelementrefs to @ xmlelements in the person class, there is no response JAXB maps them to XS: choice The XML output is the same as before, and schemagen generates the same schema as before This is an example output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <person> <first>majid</first> <last>azimi</last> <contacts> <address> <country>US</country> <city>Los Angles</city> </address> <address> <country>US</country> <city>New York</city> </address> <phone> <number>5551037</number> </phone> </contacts> </person>
This is the architecture:
<?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="address" type="address"/> <xs:element name="person" type="person"/> <xs:element name="phone" type="phone"/> <xs:complexType name="person"> <xs:sequence> <xs:element name="first" type="xs:string"/> <xs:element name="last" type="xs:string"/> <xs:element name="contacts" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="phone"/> <xs:element ref="address"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="phone"> <xs:complexContent> <xs:extension base="contactInfomation"> <xs:sequence> <xs:element name="number" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="contactInfomation" abstract="true"> <xs:sequence/> </xs:complexType> <xs:complexType name="address"> <xs:complexContent> <xs:extension base="contactInfomation"> <xs:sequence> <xs:element name="country" type="xs:string"/> <xs:element name="city" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema>
@The xmlelementref document uses it for substitution groups and XML selections I completely confused the difference between @ xmlelementrefs / @ xmlelementref and @ xmlelements / @ xmlelement Can I help you?
Solution
TL; DR
@The basic difference between xmlelement and @ xmlelementref
@The difference between xmlelement and @ xmlelementref is whether the corresponding generated element contains a local element definition or a reference to a global element definition
Selection and substitution groups
The choices in XML schema are actually supersets that can be completed by replacement groups Therefore, to simplify mapping, JAXB utilizes two mappings
JAXB and schema generation
JAXB can generate Java models from any XML schema. On the other hand, JAXB does not retain all metadata about XML schemas Therefore, JAXB cannot generate every XML schema
@Xmlelementrefs / @ xmlelementref and @ xmlrootelement
Here's what's in your model
people
I modified the mapping on the contact field to make the mapping to the address class clearer
@XmlElementWrapper(name = "contacts") @XmlElementRefs({ @XmlElementRef(name = "phone",@XmlElementRef(name = "ADDRESS",required = true) }) private final List<ContactInfomation> contacts = new ArrayList<>();
Telephone
When mapping with @ xmlelementref, the specified information needs to correspond to the global element definition provided by @ xmlrootelement or @ xmlelementdecl (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html ). by default, the root element of the person class is person
@XmlRootElement public class Person {
address
I used the @ xmlrootelement annotation to override the default name of the address class
@XmlRootElement(name="ADDRESS") public class Address extends ContactInfomation {
Generated XML schema
This is the generated schema We see that the element definition in the selection structure refers to an existing element instead of defining a local element
<xs:element name="contacts" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="phone"/> <xs:element ref="ADDRESS"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element>
@Xmlelements / @ of xmlelement
I've changed the mapping on the contact field to use @ xmlelements
people
@XmlElementWrapper(name = "contacts") @XmlElements({ @XmlElement(name = "phone-number",@XmlElement(name = "home-address",required = true) }) private final List<ContactInfomation> contacts = new ArrayList<>();
Telephone
All referenced classes do not need to use the @ xmlrootelement annotation (or have the corresponding @ xmlelementdecl annotation)
public class Phone extends ContactInfomation {
address
If his class does have @ xmlrootelement annotation, you do not need to match the @ xmlelement annotation in @ xmlelements
@XmlRootElement(name="ADDRESS") public class Address extends ContactInfomation {
Generated XML schema
This is the generated schema We see that the element definition in the selection structure is now defined as a local element
<xs:element name="contacts" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:choice maxOccurs="unbounded"> <xs:element name="phone-number" type="phone"/> <xs:element name="home-address" type="address"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element>