views:

2530

answers:

2
+1  Q: 

JAXB Types problem

I have an xsd that looks like this (snippet):

<xs:complexType name="IDType">
  <xs:choice minOccurs="1" maxOccurs="2">
    <xs:element name="FileID"    minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="IDNumber1" minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="Number"    minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="PNumber"   minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="SS"        minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="Player"    minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="Prior"     minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="BIN"       minOccurs="0" maxOccurs="1" type="an..35" />
    <xs:element name="Mutual"    minOccurs="0" maxOccurs="1" type="an..35" />
  </xs:choice>
</xs:complexType>
<xs:simpleType name="an..35">
  <xs:restriction base="an">
    <xs:maxLength value="35" />
  </xs:restriction>
</xs:simpleType>

<xs:simpleType name="an">
   <xs:restriction base="xs:string">
     <xs:pattern value="[ !-~]*" />
   </xs:restriction>
</xs:simpleType>

For some reason this is the Java code that gets generated:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "IDType", propOrder = {
    "fileID"
})
public class PatientIDType {
    @XmlElementRefs({
        @XmlElementRef(name = "FileED", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "IDNumber1", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "Number", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "PNumber", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "SS", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "Plaer", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "Prior", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "BIN", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class),
        @XmlElementRef(name = "Mutual", namespace = "http://www.surescripts.com/messaging", type = JAXBElement.class)
    })
    protected List<JAXBElement<String>> fileID;
    /**
     * Gets the value of the fileID property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the fileID property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getFileID().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     * {@link JAXBElement }{@code <}{@link String }{@code >}
     */
    public List<JAXBElement<String>> getFileID() {
        if (fileID == null) {
            fileID = new ArrayList<JAXBElement<String>>();
        }
        return this.fileID;
    }

Why is the class generated like this and simply not some kind of string array? I really don't want to have to create JAXBElements every time I want to create something?

How can I have it generate classes for each of the types that simply represent string or something like that?

Thanks in advance,

Ian

A: 

If you're using the Sun JAXB implementation, you could try compiling with the xjc:simple mode enabled. See the documentation on simplified binding for an example. It should turn

public class PatientIDType {
    protected List<JAXBElement<String>> fileID;
}

in to

public class PatientIDType {
    String fileID;
    ...
}

You'll need to compile your schema with a binding customisation file. See Kohsuke's blog for an example of how to do it.

safetydan
I tried adding this binding but still the output is the same. Am i missing something?[code]<!-- This enables the simple binding mode in JAXB. See http://weblogs.java.net/blog/kohsuke/archive/2006/03/simple_and_bett.html --> <jaxb:bindings jaxb:version="2.0" jaxb:extensionBindingPrefixes="xjc" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jaxb:globalBindings> <xjc:simple/> </jaxb:globalBindings> </jaxb:bindings>[/code]
Strange that it didn't do anything. Has it changed any of the other Java classes? The most notable thing is pluralisation of collection names. Are you using XJC directly like xjc -extension simpleBinding.schemalet abc.xsd?
safetydan
There were a couple of changes but nothing significant. I'm calling it using ant with the extension="true" attribute
+4  A: 

This code is generated because your complex type, IDType, contains a choice with a maxOccurrence greater than one, here:

<xs:choice minOccurs="1" maxOccurs="2">

The contents of this lists are elements with different names but the same type. This has no equivalent in standard object-oriented models. JAXB then uses the JAXBElement class to work around this: a JAXBElement wraps a simple object that contains the data and assigns it a QName.

Thus you can read from this list and write to the list unambiguously by providing:

  • The data object (in your case a String since all restrictions from String are represented as a Java String)
  • A JAXBElement whose getValue() method returns the string

The JAXB specification contains fairly detailed and reasonably complex explanations of how to deal with repeating choices and repeating sequences. Note that if your sequence contained objects of different types as well as different names, you would end up with List<Object>.

That was the long explanation, now here are some options:

  • If you can modify the schema, put a wrapper element around the 8 items, say, "Wrapper". Wrapper will contain a single choice of the elements; Then make IDType contain a sequence of Wrapper elements with minOccurs = 1 and maxOccurs = 2.
  • Create yourself some helper functions to quickly create the JAXBElements. JAXB puts a Factory class in your target package that can help you - for example, it contains references to the Schema namespace, etc.
xcut
Perfect answer. Thank you. Unfortunately it's an externally supplied XSD so I will have to go with the second option. Not my favorite but it will certainly work