users@jaxb.java.net

Re: Issue with types that refer to themselves, and arrays

From: Wolfgang Laun <wolfgang.laun_at_gmail.com>
Date: Tue, 16 Sep 2008 20:54:42 +0200

I don't see what you gain by establishing a schema type for your properties
that happen to be List<Group>. Since you write the Java classes anyway,
where does the "reuse" come in?

Actually, the schemagen that comes with jdk1.6.0_03 handles the
type=Group[].class
correctly.

-W

On Mon, Sep 15, 2008 at 11:30 PM, Reif, Benjamin <benjamin.reif_at_cgi.com>wrote:

> All,
>
>
>
> Sorry for the long email, but I just wanted to include the necessary detail
> for clarity. I am using JAXB annotations (2.1.6) in my Java classes to
> generate Schema / WSDL.
>
> I have many methods that use Collections, which I would like to be wrapped
> array types in the schema. However, I would like the schema to have
> seperate, named,
>
> complexTypes for the arrays so that they can be reused (@XmlElementWrapper
> seems to make an anonymous complexType inside an element,
>
> which can't be reused).
>
>
>
> I have found that simply specifying the Array class on the @XmlElement type
> attribute works in most cases, and creates a reusable Array complexType in
> the Schema:
>
>
>
> @XmlElement(name="myObjects", type=MyObject[].class, namespace="
> http://security.myProject.myCompany.com/", nillable=true, required=false)
>
> public List<MyObject> getMyObjects() {
>
> return objs;
>
> }
>
>
>
> Assuming that this method is in another class called Foo, this gives you:
>
>
>
> <xs:complexType name="Foo">
>
> <xs:sequence>
>
> <xs:element form="qualified" minOccurs="0" name="myObjects"
> nillable="true" type="tns:MyObjectArray"/>
>
> </xs:sequence>
>
> </xs:complexType>
>
>
>
> <xs:complexType final="#all" name="MyObjectArray">
>
> <xs:sequence>
>
> <xs:element maxOccurs="unbounded" minOccurs="0" name="item"
> nillable="true" type="tns:MyObject"/>
>
> </xs:sequence>
>
> </xs:complexType>
>
>
>
> The problem I have found however, is that this does not work when you have
> circular dependencies, where an object references
>
> another object, which then refers to itself. The example I'm using is that
> a User can belong to many Groups. In addition, a Group can be made up
>
> of one or more Groups as well. So I have:
>
>
>
> @XmlType(name="User", namespace="http://security.myProject.myCompany.com/",
> propOrder={""})
>
> public class User {
>
>
>
> @XmlElement(name="userGroups", type=Group[].class, namespace="
> http://security.myProject.myCompany.com/", nillable=true, required=false)
>
> public List<Group> getUserGroups() {
>
> return groups;
>
> }
>
> }
>
>
>
> @XmlType(name="Group", namespace="http://security.myProject.myCompany.com/",
> propOrder={""})
>
> public class Group {
>
>
>
> @XmlElement(name="groups", type=Group[].class, namespace="
> http://security.myProject.myCompany.com/", nillable=true, required=false)
>
> public List<Group> getGroups() {
>
> return groups;
>
> }
>
> }
>
>
>
> But when I try to annotate it this way I get:
>
>
>
> "2 counts of IllegalAnnotationExceptions Two classes have the same XML type
> name "{http://security.myProject.myCompany.com/}GroupArray<http://security.myProject.myCompany.com/%7DGroupArray>".
> Use @XmlType.name and
>
> @XmlType.namespace to assign different names to them.
>
> this problem is related to the following location:
>
> at com.myCompany.myProject.security.Group[]
>
> at public java.util.List
> com.myCompany.myProject.security.Group.getGroups()
>
> at com.myCompany.myProject.security.Group
>
> at com.myCompany.myProject.security.User"
>
>
>
> I think the problem is from
> com.sun.xml.bind.v2.model.impl.ModelBuilder.addTypeName(NonElement<T, C> r),
> where it checks if 'old' is not equal to null:
>
>
>
> private void addTypeName(NonElement<T, C> r) {
>
> QName t = r.getTypeName();
>
> if(t==null) return;
>
>
>
> TypeInfo old = typeNames.put(t,r);
>
> if(old!=null) {
>
> // collision
>
> reportError(new IllegalAnnotationException(
>
>
> Messages.CONFLICTING_XML_TYPE_MAPPING.format(r.getTypeName()),
>
> old, r ));
>
> }
>
> }
>
>
>
> I think this is incorrect, since it is possible that the type can be
> referenced multiple times from multiple classes in the same package, or even
> referenced by itself;
>
> which in this case is why it's not null and is throwing the error. I think
> the correct logic would be to implement TypeInfo.equals() method, something
> like:
>
>
>
> public boolean equals(Object obj){
>
> if(this.getClass.isAssignableFrom(obj.getClass())){
>
> TypeInfo ti = (TypeInfo)obj;
>
> if(this.getType().equals(ti.getType()) &&
> this.getTypeName().equals(ti.getTypeName())){
>
> return true;
>
> }
>
> }
>
> return false;
>
> }
>
>
>
> Then addTypeName() should check:
>
>
>
> if(old!=null && !old.equals(r)){
>
> // collision
>
> reportError(new IllegalAnnotationException(
>
>
> Messages.CONFLICTING_XML_TYPE_MAPPING.format(r.getTypeName()),
>
> old, r ));
>
> }
>
>
>
> I'm wondering if this seems like a legitimate defect and if the JAXB team
> thinks this is a reasonable solution, or if anyone else has found another
>
> way around it without having to change the source code.
>
>
>
> Thanks,
>
> Ben
>
>
>