I have a schema.xsd and bindings.xjb that I am using to generate classes with xjc. I'm trying to get xjc to generate a field that is a Map where Object vales are one of many simple or complex types (xs:choice). I don't know if what I am trying to accomplish is possible. Here are the key requirements:
- Use JAXB to marshall and unmarshall objects
- Using a java.util.Map instead of a java.util.List to track the Poc entries in ContactList
- Parsing a choice option into values that are stored in the java.util.Map
- Choice options may be complex types
I'll give sample code here:
schema.xsd
<?xml version="1.0"?>
<!-- schema.xsd -->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
elementFormDefault="qualified">
<xs:simpleType name="phonenumbertype">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:complexType name="addresstype">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="state" type="xs:string"/>
<xs:element name="zipcode" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="poctype">
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:choice>
<xs:element name="Address" type="addresstype"/>
<xs:element name="Phone" type="phonenumbertype"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="contactlisttype">
<xs:sequence>
<xs:element name="Poc" type="poctype" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="AddressBook">
<xs:complexType>
<xs:sequence>
<xs:element name="ContactList" type="contactlisttype"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
bindings.xjb
<?xml version="1.0" encoding="UTF-8"?>
<!-- bindings.xjb -->
<jxb:bindings version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
<jxb:globalBindings fixedAttributeAsConstantProperty="true"
collectionType="java.util.ArrayList"
typesafeEnumBase="xs:NCName"
choiceContentProperty="true"
typesafeEnumMemberName="generateError"
enableFailFastCheck="false"
generateIsSetMethod="false"
underscoreBinding="asCharInWord">
<!-- does not work: [ERROR] undefined simple type "contactlisttype". -->
<xjc:javaType name="java.util.Map" xmlType="contactlisttype" adapter="xjc.MapAdapater"/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
document.xml
<?xml version="1.0" encoding="UTF-8"?>
<AddressBook>
<ContactList>
<Poc>
<Name>Person1</Name>
<Address>
<street>Home Street</street>
<city>Home Town</city>
<state>Home State</state>
<zipcode>99999</zipcode>
</Address>
</Poc>
<Poc>
<Name>Person2</Name>
<PhoneNumber>8006667777</PhoneNumber>
</Poc>
</ContactList>
</AddressBook>
Right now xjc generates this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"contactList"
})
@XmlRootElement(name = "AddressBook")
public class AddressBook {
@XmlElement(name = "ContactList", required = true)
protected ContactList contactList;
But I want it to generate something similar to this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"contactList"
})
@XmlRootElement(name = "AddressBook")
public class AddressBook {
@XmlElement(name = "ContactList", required = true)
@XmlJavaTypeAdapter(MapAdapter.class)
protected Map<String, Object> contactList;
MapAdapter.java
public class MapAdapter extends XmlAdapter<Map<String, Object>, ContactList>
{
@Override
public ContactList unmarshal(Map<String, Object> v) throws Exception
{
ObjectFactory factory = new ObjectFactory();
ContactList result = factory.createContactList();
List<PointOfContact> contacts = result.getPoc();
for (Map.Entry<String, Object> entry : v.entrySet())
{
PointOfContact poc = factory.createPointOfContact();
String name = entry.getKey();
Object address = entry.getValue();
poc.setName(name);
poc.setAddressOrPhone(address);
contacts.add(poc);
}
return result;
}
@Override
public Map<String, Object> marshal(ContactList v) throws Exception
{
// predictable iteration order maintains order of XML elements
Map<String, Object> result = new LinkedHashMap<>();
List<PointOfContact> contacts = v.getPoc();
for (PointOfContact poc : contacts)
{
String key = poc.getName();
Object value = poc.getAddressOrPhone();
result.put(key, value);
}
return result;
}
}