1) This is way cool.
2) What do you think about "*Type1.java" instead of "*ANON1.java"? I think that might be a little clearer as to what this thing is. --Glen > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]] > Sent: Wednesday, March 13, 2002 10:19 AM > To: [EMAIL PROTECTED] > Subject: cvs commit: xml-axis/java/test/wsdl/refattr refattr.wsdl > > > scheu 02/03/13 07:19:27 > > Modified: java/lib wsdl4j.jar > java/src/org/apache/axis/wsdl/toJava Emitter.java > JavaDeployWriter.java JavaStubWriter.java > JavaWriterFactory.java SchemaUtils.java > SymbolTable.java Utils.java > java/test/wsdl/refattr refattr.wsdl > Log: > Changes for anonymous type processing in WSDL2Java Symbol Table. > > Problem Description: > -------------------- > An anonymous type is a type (simpleType or complexType) > that does not > have a name. Here is an example: > > ... > <element name="foo"> > <complexType> > .... > </complexType> > > The WSDL2Java symbol table uses the QName as the key to access a > symbol table entry. Since an anonymous type does not have a qname, > the qname of the containing element is used. Unfortunately it is > possible that the element is not unique, which results in a symbol > table collision. (As reported by Tom Jordahl.) > > Solution: > --------- > > 1) The first change is to give anonymous type elements unique names > to avoid symbol table collisions. The unique name must > be something > that can be determined by examining the dom tree. I chose to use > the following format for the local name: > <qname-of-containing-simple/compleType>.<qname-of-element> > If the anonymous type is used to define a global > element, its local name is: > .<qname-of-element> > > 2) Change to the SchemaUtils code that queries the qname of > an anon type. > > 3) Change to the JavaWriterFactory.javifyNames method. > This method is > enhanced to ensure that anonymous java type name > collisions don't occur. > If a name collision is detected, the suffix ANON### is > appended to the name > of the anonymous class java name to prevent the > collision (### is a unique number). > > 4) Changed the refattr.wsdl to have a anonymous type > collision similar to the > one submitted to axis-dev by Tom Jordahl. > > Phase 2: > -------- > Anonymous types for root elements are not put into the > symbol table. Instead > the emitter writer classes use the DefinedElement > information when generating code. This > can lead to some fuzzy logic and subtle bugs. (I promised > Glen last week that > I would look at changing this code.) > > Solution: > > 1) Anonymous types for root elements are added to the > symbol table just like > all other anonymous types. > > 2) The JavaWriterFactory.resolve() method is modified to ensure that > the java name of the root DefinedElement matches the java > name of its anonymous DefinedType. > > 3) Changed Utils.getNested to get the anonymous DefinedType. > > 4) Changed the emitter writeTypes() method to only process > Type entries > (not Element entries). This is an improvement, > writeTypes only deals with types! > > 5) Changed the deploy and stub writers to not register type > mappings for > Elements. (Before the deploy and stub writers had to > examine the Element > to see if it had an anonymous type...) > > * There are a number of existing testcases that use anonymous types > for root elements. All of the tests passed. > > Revision Changes Path > 1.10 +553 -414 xml-axis/java/lib/wsdl4j.jar > > <<Binary file>> > > > 1.25 +3 -1 > xml-axis/java/src/org/apache/axis/wsdl/toJava/Emitter.java > > Index: Emitter.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/Emitter.java,v > retrieving revision 1.24 > retrieving revision 1.25 > diff -u -r1.24 -r1.25 > --- Emitter.java 5 Mar 2002 14:52:06 -0000 1.24 > +++ Emitter.java 13 Mar 2002 15:19:26 -0000 1.25 > @@ -482,9 +482,11 @@ > // - we found its definition (getNode()) > // - it is referenced > // - it is not a base java type > + // - it is a Type (not an Element) > // (Note that types that are arrays are passed > to getWriter > // because they may require a Holder) > - if (type.getNode() != null && > + if (type.getNode() != null && > + type instanceof Type && > type.isReferenced() && > type.getBaseType() == null) { > Writer writer = > writerFactory.getWriter(type, symbolTable); > > > > 1.26 +3 -13 > xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaDeployWriter.java > > Index: JavaDeployWriter.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaDe > ployWriter.java,v > retrieving revision 1.25 > retrieving revision 1.26 > diff -u -r1.25 -r1.26 > --- JavaDeployWriter.java 8 Mar 2002 20:04:45 -0000 1.25 > +++ JavaDeployWriter.java 13 Mar 2002 15:19:26 -0000 1.26 > @@ -157,28 +157,18 @@ > // 1) Don't register types that are base > (primitive) types. > // If the baseType != null && getRefType() > != null this > // is a simpleType that must be registered. > - // 2) Don't register the special types for collections > - // (indexed properties) > + // 2) Don't register the special types for collections > + // (indexed properties) or element types > // 3) Don't register types that are not referenced > // or only referenced in a literal context. > if ((type.getBaseType() != null && > type.getRefType() == null) || > type instanceof CollectionType || > + type instanceof Element || > !type.isReferenced() || > type.isOnlyLiteralReferenced()) { > process = false; > } > > - > - // 4) If the type is an element, the > typemapping is only generated > - // if the element has an anonymous type. This > is a quick fix > - // until I add anonymous types as actual > symbol table elements. Scheu > - if (process && type instanceof Element) { > - Node node = > symbolTable.getTypeEntry(type.getQName(), > - > true).getNode(); > - if (node == null || > - Utils.getNodeTypeRefQName(node, > "type") != null) > - process = false; > - } > if (process) { > pw.println(" <typeMapping"); > pw.println(" xmlns:ns=\"" + > type.getQName().getNamespaceURI() + "\""); > > > > 1.42 +3 -12 > xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaStubWriter.java > > Index: JavaStubWriter.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaSt > ubWriter.java,v > retrieving revision 1.41 > retrieving revision 1.42 > diff -u -r1.41 -r1.42 > --- JavaStubWriter.java 6 Mar 2002 18:50:51 -0000 1.41 > +++ JavaStubWriter.java 13 Mar 2002 15:19:26 -0000 1.42 > @@ -402,27 +402,18 @@ > // 1) Don't register types that are base (primitive) types. > // If the baseType != null && getRefType() != null this > // is a simpleType that must be registered. > - // 2) Don't register the special types for collections > - // (indexed properties) > + // 2) Don't register the special types for collections > + // (indexed properties) or element types > // 3) Don't register types that are not referenced > // or only referenced in a literal context. > if ((type.getBaseType() != null && > type.getRefType() == null) || > type instanceof CollectionType || > + type instanceof Element || > !type.isReferenced() || > type.isOnlyLiteralReferenced()) { > process = false; > } > > - // 4) If the type is an element, the typemapping > is only generated > - // if the element has an anonymous type. This is > a quick fix > - // until I add anonymous types as actual symbol > table elements. Scheu > - if (process && type instanceof Element) { > - Node node = symbolTable.getTypeEntry(type.getQName(), > - true).getNode(); > - if (node == null || > - Utils.getNodeTypeRefQName(node, "type") != null) > - process = false; > - } > if (!process) { > return; > } > > > > 1.17 +51 -4 > xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaWriterFactory.java > > Index: JavaWriterFactory.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaWr > iterFactory.java,v > retrieving revision 1.16 > retrieving revision 1.17 > diff -u -r1.16 -r1.17 > --- JavaWriterFactory.java 27 Feb 2002 13:41:28 -0000 1.16 > +++ JavaWriterFactory.java 13 Mar 2002 15:19:27 -0000 1.17 > @@ -157,17 +157,20 @@ > } // getWriter > > /** > - * Fill in the names of each SymTabEntry with the > javaified name > + * Fill in the names of each SymTabEntry with the > javaified name. > + * Note: This method also ensures that anonymous types are > + * given unique java type names. > */ > private void javifyNames(SymbolTable symbolTable) { > + int uniqueNum = 0; > + HashMap anonQNames = new HashMap(); > Iterator it = symbolTable.getHashMap().values().iterator(); > while (it.hasNext()) { > Vector v = (Vector) it.next(); > for (int i = 0; i < v.size(); ++i) { > SymTabEntry entry = (SymTabEntry) v.elementAt(i); > > - // If it's a type, then use the referenced > type's QName to generate this type's > - // name. > + // Use the type or the referenced type's > QName to generate the java name. > if (entry instanceof TypeEntry) { > TypeEntry tEntry = (TypeEntry) entry; > String dims = tEntry.getDimensions(); > @@ -177,7 +180,28 @@ > dims += tEntry.getDimensions(); > refType = tEntry.getRefType(); > } > - > entry.setName(symbolTable.getJavaName(tEntry.getQName()) + dims); > + // Get the QName to javify > + QName typeQName = tEntry.getQName(); > + if > (typeQName.getLocalPart().lastIndexOf('.') >= 0) { > + // This is an anonymous type name. > + // Axis uses '.' as a nesting > token to generate > + // unique qnames for anonymous types. > + // Only consider the localName > after the last '.' when > + // generating the java name > + String localName = > typeQName.getLocalPart(); > + localName = > localName.substring(localName.lastIndexOf('.')+1); > + typeQName = new > QName(typeQName.getNamespaceURI(), localName); > + // If there is already an existing > type, there will be a > + // collision. If there is an > existing anon type, there will be a > + // collision. In both cases, the > java type name should be mangled. > + if (symbolTable.getType(typeQName) > != null || > + anonQNames.get(typeQName) != null) { > + localName += "ANON" + uniqueNum++; > + typeQName = new > QName(typeQName.getNamespaceURI(), localName); > + } > + anonQNames.put(typeQName, typeQName); > + } > + > entry.setName(symbolTable.getJavaName(typeQName) + dims); > } > > // If it is not a type, then use this > entry's QName to generate its name. > @@ -245,6 +269,15 @@ > if (entry instanceof Element) { > > entry.setName(mangleName(entry.getName(), > "_ElemType")); > + // If this global element was > defined using > + // an anonymous type, then > need to change the > + // java name of the anonymous > type to match. > + QName anonQName = new > QName(entry.getQName().getNamespaceURI(), > + > "." + entry.getQName().getLocalPart()); > + TypeEntry anonType = > symbolTable.getType(anonQName); > + if (anonType != null) { > + anonType.setName(entry.getName()); > + } > } > else if (entry instanceof TypeEntry) { > // Search all other types for > java names that match this one. > @@ -508,6 +541,20 @@ > p.type.setDynamicVar( > > JavaTypeWriter.HOLDER_IS_NEEDED, > new Boolean(true)); > + > + // If the type is a > DefinedElement, need to > + // set HOLDER_IS_NEEDED on > the anonymous type. > + QName anonQName = SchemaUtils. > + > getElementAnonQName(p.type.getNode()); > + if (anonQName != null) { > + TypeEntry anonType = > + > symbolTable.getType(anonQName); > + if (anonType != null) { > + anonType.setDynamicVar( > + > JavaTypeWriter.HOLDER_IS_NEEDED, > + new Boolean(true)); > + } > > + } > } > } > } > > > > 1.14 +27 -4 > xml-axis/java/src/org/apache/axis/wsdl/toJava/SchemaUtils.java > > Index: SchemaUtils.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/Schema > Utils.java,v > retrieving revision 1.13 > retrieving revision 1.14 > diff -u -r1.13 -r1.14 > --- SchemaUtils.java 11 Mar 2002 16:25:32 -0000 1.13 > +++ SchemaUtils.java 13 Mar 2002 15:19:27 -0000 1.14 > @@ -324,17 +324,40 @@ > QName nodeName = Utils.getNodeNameQName(elementNode); > BooleanHolder forElement = new BooleanHolder(); > QName nodeType = > Utils.getNodeTypeRefQName(elementNode, forElement); > - if (nodeType == null) { // The element may use an > anonymous type > - nodeType = nodeName; > - forElement.value = false; > + if (nodeType == null) { // The element may use an > anonymous type > + nodeType = getElementAnonQName(elementNode); > > + forElement.value = false; > } > - > + > TypeEntry type = (TypeEntry) > symbolTable.getTypeEntry(nodeType, forElement.value); > if (type != null) { > v.add(type); > v.add(nodeName.getLocalPart()); > } > return v; > + } > + > + /** > + * Returns the WSDL2Java QName for the anonymous type > of the element > + * or null. > + */ > + public static QName getElementAnonQName(Node node) { > + QName nodeKind = Utils.getNodeQName(node); > + if (nodeKind != null && > + nodeKind.getLocalPart().equals("element") && > + Constants.isSchemaXSD(nodeKind.getNamespaceURI())) { > + NodeList children = node.getChildNodes(); > + for (int j = 0; j < children.getLength(); j++) { > + QName kind = Utils.getNodeQName(children.item(j)); > + if (kind != null && > + (kind.getLocalPart().equals("complexType") || > + kind.getLocalPart().equals("simpleType")) && > + > Constants.isSchemaXSD(kind.getNamespaceURI())) { > + return > Utils.getNodeNameQName(children.item(j)); > + } > + } > + } > + return null; > } > > /** > > > > 1.43 +1 -14 > xml-axis/java/src/org/apache/axis/wsdl/toJava/SymbolTable.java > > Index: SymbolTable.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/Symbol > Table.java,v > retrieving revision 1.42 > retrieving revision 1.43 > diff -u -r1.42 -r1.43 > --- SymbolTable.java 11 Mar 2002 16:25:32 -0000 1.42 > +++ SymbolTable.java 13 Mar 2002 15:19:27 -0000 1.43 > @@ -613,21 +613,8 @@ > */ > private void createTypeFromDef(Node node, boolean isElement, > boolean belowSchemaLevel) throws IOException { > - // See if this is an anonymous complexType for a > global element > - // If it is, the element in the dictionary is used. > - QName qName = null; > - TypeEntry anonType = null; > - if (!isElement && > - Utils.getAttribute(node, "name") == null) { > - qName = Utils.getNodeNameQName(node); > - if (qName != null && > - getElement(qName) != null) { // Element > exists in dictionary so use it. > - return; > - } > - } > - > // Get the QName of the node's name attribute value > - qName = Utils.getNodeNameQName(node); > + QName qName = Utils.getNodeNameQName(node); > if (qName != null) { > > // If the qname is already registered as a base type, > > > > 1.18 +27 -88 > xml-axis/java/src/org/apache/axis/wsdl/toJava/Utils.java > > Index: Utils.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/Utils.java,v > retrieving revision 1.17 > retrieving revision 1.18 > diff -u -r1.17 -r1.18 > --- Utils.java 11 Mar 2002 16:25:32 -0000 1.17 > +++ Utils.java 13 Mar 2002 15:19:27 -0000 1.18 > @@ -97,93 +97,6 @@ > return name; > } // capitalizeFirstChar > > - > - > - /** > - * Some QNames represent base types. This routine returns the > - * name of the base java type or null. > - * (These mappings based on JSR-101 version 0.6 Public Draft) > - * ---------------------------------------------------------- > - * Note that the Schema simple types map to different > java types > - * depending on whether the nillable flag is set. This routine > - * assumes nillable is false. > - * ---------------------------------------------------------- > - * @param QName > - */ > - /* > - public static String getBaseJavaName(QName qName) { > - String localName = qName.getLocalPart(); > - if (Constants.isSchemaXSD(qName.getNamespaceURI())) { > - if (localName.equals("string")) { > - return "java.lang.String"; > - } else if (localName.equals("integer")) { > - return "java.math.BigInteger"; > - } else if (localName.equals("int")) { > - return "int"; > - } else if (localName.equals("long")) { > - return "long"; > - } else if (localName.equals("short")) { > - return "short"; > - } else if (localName.equals("decimal")) { > - return "java.math.BigDecimal"; > - } else if (localName.equals("float")) { > - return "float"; > - } else if (localName.equals("double")) { > - return "double"; > - } else if (localName.equals("boolean")) { > - return "boolean"; > - } else if (localName.equals("byte")) { > - return "byte"; > - } else if (localName.equals("QName")) { > - return "javax.xml.rpc.namespace.QName"; > - } else if (localName.equals("dateTime")) { > - return "java.util.Date"; // > Should be Calendar, but Calendar is abstract! > - } else if (localName.equals("base64Binary")) { > - return "byte[]"; > - } else if (localName.equals("hexBinary")) { > - return "byte[]"; > - } else if (localName.equals("date")) { // > Not defined in JSR-101 > - return "java.util.Date"; > - } else if (localName.equals("void")) { // > Not defined in JSR-101 > - return "void"; > - } else if (localName.equals("anyType")) { > - return "java.lang.Object"; > - } > - } > - else if (Constants.isSOAP_ENC(qName.getNamespaceURI())) { > - if (localName.equals("string")) { > - return "java.lang.String"; > - } else if (localName.equals("int")) { > - return "java.lang.Integer"; > - } else if (localName.equals("short")) { > - return "java.lang.Short"; > - } else if (localName.equals("decimal")) { > - return "java.math.BigDecimal"; > - } else if (localName.equals("float")) { > - return "java.lang.Float"; > - } else if (localName.equals("double")) { > - return "java.lang.Double"; > - } else if (localName.equals("boolean")) { > - return "java.lang.Boolean"; > - } else if (localName.equals("base64")) { > - return "java.lang.Byte[]"; > - } else if (localName.equals("byte")) { > - return "java.lang.Byte"; > - } else if (localName.equals("Array")) { // > Support for JAX-RPC Array > - return "Object[]"; > - } else if (localName.equals("Vector")) { // > Not defined in JSR-101 > - return "java.util.Vector"; > - } > - } > - // special "java" namesapce means straight java types > - // So "java:void" maps to "void" > - else if (qName.getNamespaceURI().equals("java")) { > // Not defined in JSR-101 > - return localName; > - } > - return null; > - } > - */ > - > /** > * getNillableQName returns the QName to use if the > nillable=true > * attribute is used. > @@ -327,7 +240,23 @@ > // the complexType may be anonymous, which is why > the getScopedAttribute > // method is used. > if (localName == null) { > - localName = getScopedAttribute(node, "name"); > + localName = ""; > + Node search = node.getParentNode(); > + while(search != null) { > + QName kind = getNodeQName(search); > + if (kind.getLocalPart().equals("schema")) { > + search = null; > + } else if (kind.getLocalPart().equals("element")) { > + localName = "." + > getNodeNameQName(search).getLocalPart(); > + search = search.getParentNode(); > + } else if > (kind.getLocalPart().equals("complexType") || > + > kind.getLocalPart().equals("simpleType")) { > + localName = > getNodeNameQName(search).getLocalPart() + localName; > + search = null; > + } else { > + search = search.getParentNode(); > + } > + } > } > if (localName == null) > return null; > @@ -707,6 +636,16 @@ > } > } > } > + > + // Get the anonymous type of the element > + QName anonQName = SchemaUtils.getElementAnonQName(type); > + if (anonQName != null) { > + TypeEntry anonType = symbolTable.getType(anonQName); > + if (anonType != null && !types.contains(anonType)) { > + types.add(anonType); > + } > + } > + > // Process extended types > TypeEntry extendType = > SchemaUtils.getComplexElementExtensionBase(type, symbolTable); > if (extendType != null) { > > > > 1.4 +21 -1 xml-axis/java/test/wsdl/refattr/refattr.wsdl > > Index: refattr.wsdl > =================================================================== > RCS file: /home/cvs/xml-axis/java/test/wsdl/refattr/refattr.wsdl,v > retrieving revision 1.3 > retrieving revision 1.4 > diff -u -r1.3 -r1.4 > --- refattr.wsdl 25 Jan 2002 18:31:53 -0000 1.3 > +++ refattr.wsdl 13 Mar 2002 15:19:27 -0000 1.4 > @@ -28,13 +28,33 @@ > <xsd:all> > <xsd:element name="areaCode" type="xsd:int"/> > <xsd:element name="exchange" type="xsd:string"/> > - <xsd:element name="number" type="xsd:string"/> > + <xsd:element name="number"> > + <xsd:complexType> > + <xsd:simpleContent> > + <xsd:extension base = "xsd:string"> > + <xsd:attribute name= "length" > type="xsd:int" /> > + </xsd:extension> > + </xsd:simpleContent> > + </xsd:complexType> > + </xsd:element> > </xsd:all> > </xsd:complexType> > > <xsd:complexType name="example"> > <xsd:all> > <xsd:element name="address" type="soapenc:string"/> > + <!-- both example and phone contain anonymous > types of number elements. --> > + <!-- This should result in two Number > classes...one which has a mangled name --> > + <xsd:element name="number"> > + <xsd:complexType> > + <xsd:simpleContent> > + <xsd:extension base = "xsd:string"> > + <xsd:attribute name= "theLength" > type="xsd:int" /> > + </xsd:extension> > + </xsd:simpleContent> > + </xsd:complexType> > + </xsd:element> > + > </xsd:all> > </xsd:complexType> > > > > >