4
votes

Suppose I have the following java class that maps to the request-body of my REST service to search users.

@XmlRootElement(name = "SearchParams")
@XmlType(propOrder = {})
public class SearchParams {

  private String firstname;
  private String lastname;
  private List<String> role;

  ...
}

Note the propOrder parameter of the @XmlType annotation - it declares that the order in which representing individual attributes appear in an XML file does not matter and thus an xsd:all should be used instead of xsd:sequence in the generated XSD schema.

However, as you can see, one of the attributes (the role attribute) is a list and thus corresponds to an element with an unbounded maxOccurs.

It seems that an element with an unbounded maxOccurs is not allowed within an xsd:all complexType. How do I avoid this problem?

Note that, unlike role, the firstname and lastname have maxOccurs of 1. I therefore cannot use an unbounded xsd:choice instead of xsd:all either.

1

1 Answers

5
votes

Assuming you can still modify this model, you could just wrap the role list in its own type, so you would end up with a <roles> element with a list of <role>s

<SearchParams>
    <firstname>firstname</firstname>
    <lastname>lastname</lastname>
    <roles>
        <role>role</role>
    </roles>
</SearchParams>

xsd would just be

<xsd:schema ... >

    <xsd:element name="SearchParams">
        <xsd:complexType>
            <xsd:all>
                <xsd:element name="firstname" type="xsd:string" />
                <xsd:element name="lastname" type="xsd:string" />
                <xsd:element name="roles" type="Roles" />
            </xsd:all>
        </xsd:complexType>
    </xsd:element>

    <xsd:complexType name="Roles">
        <xsd:sequence>
            <xsd:element name="role" type="xsd:string" maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>

And you'd have two classes. The Roles class containing the list. IMO, this is a cleaner approach. (you could just make Roles anonymous, but then you'd be stuck with a static inner class)

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {

})
@XmlRootElement(name = "SearchParams")
public class SearchParams {

    @XmlElement(required = true)
    protected String firstname;
    @XmlElement(required = true)
    protected String lastname;
    @XmlElement(required = true)
    protected Roles roles;
    ...
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Roles", propOrder = {
    "role"
})
public class Roles {

    @XmlElement(required = true)
    protected List<String> role;
    ...
}

UPDATE

"If I could change the model class this way than this would look like a great way to solve this issue. Unfortunately I am only allowed to change the annotations"

You could use @XmlList.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {

})
@XmlRootElement(name = "SearchParams")
public class SearchParams {

    @XmlElement(required = true)
    protected String firstname;
    @XmlElement(required = true)
    protected String lastname;
    @XmlList
    @XmlElement(required = true)
    protected List<String> role;
    ...
}

xsd would look like

<xsd:element name="SearchParams">
    <xsd:complexType>
        <xsd:all>
            <xsd:element name="firstname" type="xsd:string" />
            <xsd:element name="lastname" type="xsd:string" />
            <xsd:element name="role">
                <xsd:simpleType>
                    <xsd:list itemType="xsd:string" />
                </xsd:simpleType>
            </xsd:element>
        </xsd:all>
    </xsd:complexType>
</xsd:element>

Note: As noted here, this method is a "dangerous", the solution in the beginning of my post is preferred over using a list of string types. But in your specific case, not sure if I see another way