Seems reasonable.
There is a fine line between mangling names in a way that makes sense and
also mangling them so they won't collide with something else.
I'll make the change right now.
Rich Scheuerle
XML & Web Services Development
512-838-5115 (IBM TL 678-5115)
Glen Daniels
<gdaniels@macrome To: "'[EMAIL PROTECTED]'"
<[EMAIL PROTECTED]>
dia.com> cc:
Subject: RE: cvs commit:
xml-axis/java/test/wsdl/refattr refattr.wsdl
03/13/2002 09:41
AM
Please respond to
axis-dev
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>
>
>
>
>
>