Hi, here's a patch for the situation where the same element can occur more than once in a complex type (e.g., in different places within a sequence.)
Also, the default attribute didn't seem to work with attributese of types NMTOKENS (at least not with -type j2), so I fixed that (for -type j2).
This is a diff against the latest version in cvs.
Attached is a very simple schema on which the current version of castor fails, and the patched version succeeds.
Hope this is useful.
Thanks Bruce Cota Unicon, Inc.
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/castor/builder/CollectionInfo.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 CollectionInfo.java
--- src/main/org/exolab/castor/builder/CollectionInfo.java 3 Mar 2003 07:07:41
-0000 1.1.1.1
+++ src/main/org/exolab/castor/builder/CollectionInfo.java 18 May 2003 17:52:20
-0000
@@ -55,6 +55,7 @@
import org.exolab.castor.xml.JavaNaming;
import org.exolab.javasource.*;
+import java.util.StringTokenizer;
import java.util.Vector;
/**
@@ -77,6 +78,7 @@
private FieldInfo content = null;
private String elementName;
+ protected Vector initValues = null; //initial values for the collection
/**
* Creates a new CollectionInfo
@@ -107,6 +109,7 @@
public String getReadMethodName() {
StringBuffer sb = new StringBuffer("get");
sb.append(JavaNaming.toJavaClassName(getElementName()));
+ sb.append(getSuffix());
// fix for avoiding compilation conflict sb.append("List");
return sb.toString();
} //-- getReadMethodName
@@ -115,9 +118,25 @@
StringBuffer sb = new StringBuffer();
sb.append("add");
sb.append(JavaNaming.toJavaClassName(getElementName()));
+ sb.append(getSuffix());
return sb.toString();
} //-- getWriteMethodName
+
+ /* Sets the default value for this FieldInfo.
+ * This must be a WS-separated list of strings.
+ * @param defaultValue the default value
+ **/
+ public void setDefaultValue(String defaultValue) {
+ StringTokenizer tokenizer = new StringTokenizer(defaultValue);
+ int numTokens = tokenizer.countTokens();
+ initValues = new Vector(numTokens);
+ while (tokenizer.hasMoreElements()) {
+ initValues.add(tokenizer.nextToken());
+ }
+ } //-- setDefaultValue;
+
+
//------------------/
//- Public Methods -/
//------------------/
@@ -143,6 +162,7 @@
//---------------------/
String cName = JavaNaming.toJavaClassName(getElementName());
+ cName += getSuffix();
method = new JMethod(null, "add"+cName);
jClass.addMethod(method);
method.addException(SGTypes.IndexOutOfBoundsException);
Index: src/main/org/exolab/castor/builder/CollectionInfoJ2.java
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/castor/builder/CollectionInfoJ2.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 CollectionInfoJ2.java
--- src/main/org/exolab/castor/builder/CollectionInfoJ2.java 3 Mar 2003 07:07:42
-0000 1.1.1.1
+++ src/main/org/exolab/castor/builder/CollectionInfoJ2.java 18 May 2003 17:52:20
-0000
@@ -85,8 +85,26 @@
**/
public void generateInitializerCode(JSourceCode jsc) {
jsc.add(getName());
- jsc.append(" = new ArrayList();");
- } //-- generateConstructorCode
+
+ int numValues = -1;
+ if (initValues != null && initValues.size() > 0) {
+ numValues = initValues.size();
+ }
+
+ jsc.append(" = new ArrayList(");
+ if (numValues > 0) {
+ jsc.append("" + initValues.size());
+ }
+ jsc.append(");");
+
+ for (int i=0; i<numValues; ++i) {
+ jsc.add(getName());
+ jsc.append(".add(\"");
+ jsc.append((String)initValues.get(i));
+ jsc.append("\");");
+ }
+
+ } //-- generateConstructorCode
//------------------/
//- Public Methods -/
@@ -109,6 +127,7 @@
JSourceCode jsc = null;
String cName = JavaNaming.toJavaClassName(getElementName());
+ cName += getSuffix();
//-- add{Name}(Object)
method = new JMethod(null, "add"+cName);
@@ -180,7 +199,7 @@
//-- Reference setter (non type-safe)
String suffix =
SourceGenerator.getProperty(this.REFERENCE_SUFFIX_PROPERTY,
"AsReference");
- method = new JMethod(null, "set" + cName + suffix);
+ method = new JMethod(null, "set" + cName);
method.addParameter(vParam);
jClass.addMethod(method);
createSetCollectionReferenceMethod(method);
@@ -514,7 +533,8 @@
**/
public void createSetCollectionMethod(JMethod method) {
- String cName = JavaNaming.toJavaMemberName(getElementName());
+ String cName = JavaNaming.toJavaMemberName(getElementName())
+ + getSuffix();
//-- get param name
String paramName = method.getParameter(0).getName();
@@ -570,7 +590,8 @@
**/
public void createSetCollectionReferenceMethod(JMethod method) {
- String cName = JavaNaming.toJavaMemberName(getElementName());
+ String cName = JavaNaming.toJavaMemberName(getElementName())
+ + getSuffix();
//-- get param name
String paramName = method.getParameter(0).getName();
Index: src/main/org/exolab/castor/builder/FieldInfo.java
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/castor/builder/FieldInfo.java,v
retrieving revision 1.2
diff -u -r1.2 FieldInfo.java
--- src/main/org/exolab/castor/builder/FieldInfo.java 8 Mar 2003 07:35:42 -0000
1.2
+++ src/main/org/exolab/castor/builder/FieldInfo.java 18 May 2003 17:52:21 -0000
@@ -63,7 +63,9 @@
/**
* The Java name for Members described by this FieldInfo
**/
- private String name = null;
+ private String _suffix = "";
+
+ private String name = null; //Added to method names to make sure they are unique
private ClassInfo declaringClassInfo = null;
@@ -494,6 +496,23 @@
public String getName() {
return this.name;
} //-- getName
+
+ /**
+ * Returns the suffix used to methods unique.
+ * @return the suffix
+ **/
+ public String getSuffix() {
+ return this._suffix;
+ }
+
+ /**
+ * Sets the suffix used to methods unique.
+ * @param suffix
+ **/
+ public void setSuffix(String suffix) {
+ this._suffix = suffix;
+ }
+
/**
* Returns true if this FieldInfo represents a bound property
Index: src/main/org/exolab/castor/builder/MemberFactory.java
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/castor/builder/MemberFactory.java,v
retrieving revision 1.2
diff -u -r1.2 MemberFactory.java
--- src/main/org/exolab/castor/builder/MemberFactory.java 3 Mar 2003 09:57:14
-0000 1.2
+++ src/main/org/exolab/castor/builder/MemberFactory.java 18 May 2003 17:52:21
-0000
@@ -58,6 +58,7 @@
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.HashMap;
/**
* @author <a href="mailto:[EMAIL PROTECTED]">Keith Visco</a>
@@ -179,16 +180,18 @@
*
* @param component the XMLBindingComponent to create the
* FieldInfo for
+ * @param resolver
+ * @param usedNames HashMap of field names already used (to avoid conflicts)
* @return the FieldInfo for the given attribute declaration
*/
public FieldInfo createFieldInfo
- (XMLBindingComponent component, ClassInfoResolver resolver)
+ (XMLBindingComponent component, ClassInfoResolver resolver, HashMap usedNames)
{
String xmlName = component.getXMLName();
- String memberName = component.getJavaMemberName();
- if (!memberName.startsWith("_"))
- memberName = "_"+memberName;
+ String memberName = getMemberName(component);
+ String suffix = uniqueSuffix(memberName, usedNames);
+ memberName += suffix;
XMLType xmlType = component.getXMLType();
ClassInfo classInfo = resolver.resolve(component);
@@ -389,7 +392,8 @@
}
//don't generate code for date/time type since the constructor that parses
//a string is throwing exception
- else if (!xsType.getJType().isPrimitive() && !xsType.isDateTime()) {
+ else if (!xsType.getJType().isPrimitive() && !xsType.isDateTime()
+ && !(fieldInfo instanceof CollectionInfo)) {
//XXX This works only if a constructor
//XXX with String as parameter exists
value = "new "+xsType.getJType().toString()+"(\""+value+"\")";
@@ -504,5 +508,40 @@
}
return new String(newChars,0,count);
}
+
+ /**
+ * Factored out of createFieldInfo(XMLBindingComponent, ClassInfoResolver)
+ * Create a member name from an XMLBindingComponent.
+ * @param component
+ * @return the name
+ */
+ public static String getMemberName(XMLBindingComponent component) {
+ String memberName = component.getJavaMemberName();
+ if (!memberName.startsWith("_"))
+ memberName = "_"+memberName;
+ return memberName;
+ }
+
+ /**
+ * Utility for generating a unique name that is not already present in a
HashMap.
+ * @param name
+ * @param HashMap
+ * @return a suffix that will make the name unique. The name+suffix is also
added to the map.
+ */
+ public static String uniqueSuffix(String name, HashMap usedNames) {
+ if (usedNames.get(name) == null) {
+ usedNames.put(name, "true");
+ return "";
+ } else {
+ int namect = 1;
+ while (usedNames.get(name+"_"+namect) != null) {
+ namect += 1;
+ }
+ String suffix = "_" + namect;
+ usedNames.put(name+suffix, "true");
+ return suffix;
+ }
+ }
+
} //-- MemberFactory
Index: src/main/org/exolab/castor/builder/SourceFactory.java
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/castor/builder/SourceFactory.java,v
retrieving revision 1.4
diff -u -r1.4 SourceFactory.java
--- src/main/org/exolab/castor/builder/SourceFactory.java 24 Apr 2003 02:07:49
-0000 1.4
+++ src/main/org/exolab/castor/builder/SourceFactory.java 18 May 2003 17:52:23
-0000
@@ -60,6 +60,7 @@
import org.exolab.javasource.*;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Vector;
/**
@@ -395,6 +396,7 @@
//-- create main group class
String fname = component.getJavaClassName() + ITEM_NAME;
fname = JavaNaming.toJavaMemberName(fname, false);
+ fname = jClass.uniqueFieldName(fname);
FieldInfo fInfo = null;
if (createForGroup) {
@@ -1192,6 +1194,9 @@
if (complexType == null)
return;
+ //track field names used to avoid conflicts
+ HashMap namesUsed = new HashMap();
+
Enumeration enum = complexType.getAttributeDecls();
XMLBindingComponent component = new XMLBindingComponent();
if (_binding != null) component.setBinding(_binding);
@@ -1210,7 +1215,7 @@
createSourceCode(sType, state.getSGStateInfo());
}
}
- FieldInfo fieldInfo = memberFactory.createFieldInfo(component, state);
+ FieldInfo fieldInfo = memberFactory.createFieldInfo(component, state,
namesUsed);
handleField(fieldInfo, state);
}
return;
@@ -1322,6 +1327,7 @@
//------------------------------/
Enumeration enum = contentModel.enumerate();
+ HashMap namesUsed = new HashMap();
FieldInfo fieldInfo = null;
XMLBindingComponent component = new XMLBindingComponent();
@@ -1336,7 +1342,7 @@
//-- handle element declarations
case Structure.ELEMENT:
- fieldInfo = memberFactory.createFieldInfo(component, state);
+ fieldInfo = memberFactory.createFieldInfo(component, state,
namesUsed);
//-- Fix for element declarations being used in
//-- a group with minOccurs = 0;
//-- (kvisco - 20021007)
@@ -1367,7 +1373,8 @@
(contentModel instanceof ModelGroup)) )
{
fieldInfo = memberFactory.createFieldInfo(component,
-
state.getSGStateInfo());
+
state.getSGStateInfo(),
+
namesUsed);
handleField(fieldInfo, state);
} else {
//--else we just flatten the group
@@ -1385,7 +1392,8 @@
//that is referring to a model group in order
//not to loose the Particle information
fieldInfo = memberFactory.createFieldInfo(component,
- state.getSGStateInfo());
+
state.getSGStateInfo(),
+
namesUsed);
handleField(fieldInfo, state);
break;
} else {
Index: src/main/org/exolab/castor/xml/schema/ContentModelGroupImpl.java
===================================================================
RCS file:
/cvs/castor/castor/src/main/org/exolab/castor/xml/schema/ContentModelGroupImpl.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ContentModelGroupImpl.java
--- src/main/org/exolab/castor/xml/schema/ContentModelGroupImpl.java 3 Mar 2003
07:09:30 -0000 1.1.1.1
+++ src/main/org/exolab/castor/xml/schema/ContentModelGroupImpl.java 18 May 2003
17:52:24 -0000
@@ -102,11 +102,14 @@
String key = "element:"+name;
//-- check for naming collisions
if (_resolver.resolve(key) != null) {
- String err = "An element declaration with the given name, ";
- err += name + ", already exists in this scope.";
- throw new SchemaException(err);
- }
-
+ int namect = 1;
+ do {
+ name = elementDecl.getName() + "_" + namect++;
+ key = "element:"+name;
+ } while (_resolver.resolve(key) != null);
+ elementDecl.setName(name);
+ }
+
_resolver.addResolvable(key, elementDecl);
//-- add to content model
@@ -345,4 +348,4 @@
} //-- getParticleCount
-} //-- ContentModelGroup
\ No newline at end of file
+} //-- ContentModelGroup
Index: src/main/org/exolab/javasource/JClass.java
===================================================================
RCS file: /cvs/castor/castor/src/main/org/exolab/javasource/JClass.java,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 JClass.java
--- src/main/org/exolab/javasource/JClass.java 3 Mar 2003 07:09:53 -0000 1.1.1.1
+++ src/main/org/exolab/javasource/JClass.java 18 May 2003 17:52:25 -0000
@@ -167,11 +167,12 @@
}
String name = jField.getName();
-
- if (_fields.get(name) != null) {
- String err = "duplicate name found: " + name;
- throw new IllegalArgumentException(err);
- }
+
+ if (_fields.get(name) != null) {
+ String err = "duplicate name found: " + name;
+ throw new IllegalArgumentException(err);
+ }
+
_fields.put(name, jField);
// if member is of a type not imported by this class
@@ -774,7 +775,32 @@
_superClass = superClass;
} //-- setSuperClass
-
+ /**
+ * Do we already have this field?
+ * @param fieldName
+ * return boolean
+ */
+ public boolean hasField(String fieldName) {
+ return (_fields.get(fieldName) != null);
+ }
+
+
+ /**
+ * Get a unique name that the class does not already have.
+ * @param name
+ * @param hasMapIndex
+ **/
+ public String uniqueFieldName(String name) {
+ if (!hasField(name)) {
+ return name;
+ } else {
+ int namect = 1;
+ while (hasField(name + "_" + namect)) {
+ namect += 1;
+ }
+ return name + "_" + namect;
+ }
+ }
/**
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="redundant" type="xs:string"/> <xs:element name="testElement"> <xs:complexType> <xs:sequence> <xs:element ref="redundant" minOccurs="0"/> <xs:element name="middle" minOccurs="0" type="xs:string"/> <xs:element ref="redundant" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
