Thanks for the reply,
I think you get more re-use because I can reference use type="
tns:GroupArray" in other elements. Otherwise it comes out looking
something like:
<xs:element form="qualified" minOccurs="0"
name="groups" nillable="true">
<xs:complexType>
<xs:sequence>
<xs:element form="qualified"
maxOccurs="unbounded" minOccurs="0" name="Group" nillable="true"
type="ns0:Group"/>
</xs:sequence>
</xs:complexType>
</xs:element>
So, every object that uses a collection of Group objects must have this
whole block redefined. Anyway, re-use isn't really the important thing
here. It's a difference in the style of the schema definition. Other
tools that I'm using don't seem to work with the above, however they do
when it's a separate type <xs:complexType final="#all"
name="GroupArray">. In any case, annotating my method like this:
@XmlElement(name="groups", type=Group[].class,
namespace="
http://security.myProject.myCompany.com/", nillable=true,
required=false)
public List<Group> getGroups() {
return groups;
}
Is perfectly valid, but JAXB chokes on it when there's a circular
dependency situation (i.e. the Group object contains other Group
object), however it seems to work fine in all other cases.
Unfortunately we also have to use JDK 1.5, so using 1.6 isn't an option.
Ben
________________________________
From: Wolfgang Laun [mailto:wolfgang.laun_at_gmail.com]
Sent: Tuesday, September 16, 2008 2:55 PM
To: users_at_jaxb.dev.java.net
Subject: Re: Issue with types that refer to themselves, and arrays
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