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/JavaDeployWriter.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/JavaStubWriter.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/JavaWriterFactory.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/SchemaUtils.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/SymbolTable.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>