I agree that you need a separate list to pass the attribute names/types. I was simply pointing out a potential problem. Perhaps the solution is to change the getNestedTypes method to invoke both methods..
The only simpleTypes currently supported are enumeration types. Your example is a derivation of a complexType from a simple type, which is listed in JSR101 table 18-1 as optional support. I don't know what "derivation of a complexType from a simple type" means :-). I will need to look this up in the spec. After you are done making your changes, I would be glad to look at what you did and perhaps add the rest of the simpleType implementation. Also we may need to implement support for <group> elements. Be on the lookout for interop tests that have <group>. Thanks, Rich Scheuerle XML & Web Services Development 512-838-5115 (IBM TL 678-5115) Tom Jordahl <tomj@macromedia. To: "'[EMAIL PROTECTED]'" <[EMAIL PROTECTED]> com> cc: Subject: RE: cvs commit: xml-axis/java/src/org/apache/axis/encoding/ser Be 02/21/2002 02:36 anSerializer.java PM Please respond to axis-dev Rich, I think I do want to call the new attribute function, but I need to pass in a separate list of attribute names/types to the JavaWriter so I can distinguish them. Some of the symbolTable type stuff is a bit confusing, so I would welcome your help in this area. By the way, the interop test I am working on has this type in it: <complexType name="Document"> <simpleContent> <extension base="string"> <xsd:attribute name="ID" type="string" /> </extension> </simpleContent> </complexType> We currently don't look at this (simpleContent) at all. -- Tom Jordahl Macromedia -----Original Message----- From: R J Scheuerle Jr [mailto:[EMAIL PROTECTED]] Sent: Thursday, February 21, 2002 3:00 PM To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: cvs commit: xml-axis/java/src/org/apache/axis/encoding/ser BeanSerializer.java Tom, I would have expected that your new getComplexElementAttributes should have been called within getComplexElementTypesAndNames. The getComplexElementTypesAndNames was intended to return the names and types of all of the contained fields....and attributes is now considered to be one of those contained fields. And this code is used in the reference checking. Rich Scheuerle XML & Web Services Development 512-838-5115 (IBM TL 678-5115) [EMAIL PROTECTED] To: [EMAIL PROTECTED] 02/21/2002 12:51 cc: PM Subject: cvs commit: xml-axis/java/src/org/apache/axis/encoding/ser Please respond to BeanSerializer.java axis-dev tomj 02/02/21 10:51:24 Modified: java/test/wsdl Wsdl2javaTestSuite.xml java/src/org/apache/axis/wsdl/fromJava Types.java java/src/org/apache/axis/wsdl/toJava SymbolTable.java SchemaUtils.java JavaTypeWriter.java JavaComplexTypeWriter.java java/src/org/apache/axis/utils resources.properties java/src/org/apache/axis/encoding/ser BeanSerializer.java Log: Support for <attribute> WSDL (required for interop tests). WSDL2Java will generate bean fields for XML element attributes if specified in the WSDL. It wil also generate a getAttributeElements() static function in the bean that the bean serializer/deserializer uses. (The modifications to the serialization code have already been committed.) Sample: public class AccessPoint implements java.io.Serializable { private String element; private String myAttribute; // attribute ... public static java.util.Vector getAttributeElements() { java.util.Vector v = new java.util.Vector(); v.add("myAttribute"); return v; } } Java2WSDL will generate <attribute> in the type schema for beans that have the getAttributeElements() method to id which fields should be attributes. This involved moving the WSDL type generation for beans out of Java2WSDL and in to the serializer itself. TBD: - we do not handle all forms of attributes and the UDDI WSDL in our test suite is commented out (this WSDL uses LOTS of attributes). - The generation of type Schema should live in the serializers for all types. Currently only Map and Bean have this code. - For command line Java2WSDL, type serializers are generally not registered, so we default to the BeanSerializer for everything that isn't built in. Revision Changes Path 1.77 +2 -0 xml-axis/java/test/wsdl/Wsdl2javaTestSuite.xml Index: Wsdl2javaTestSuite.xml =================================================================== RCS file: /home/cvs/xml-axis/java/test/wsdl/Wsdl2javaTestSuite.xml,v retrieving revision 1.76 retrieving revision 1.77 diff -u -r1.76 -r1.77 --- Wsdl2javaTestSuite.xml 20 Feb 2002 20:41:14 -0000 1.76 +++ Wsdl2javaTestSuite.xml 21 Feb 2002 18:51:23 -0000 1.77 @@ -565,6 +565,7 @@ </wsdl2java> <!-- UDDI 1.0 WSDL's --> +<!-- tomj: turn these off while attribute processing is in flux <wsdl2java url="http://www.uddi.org/wsdl/inquire_v1.wsdl" output ="build/work" testcase="no" @@ -585,6 +586,7 @@ <mapping namespace="urn:uddi-org:api" package="org.uddi.api"/> <mapping namespace="urn:uddi-org:publication" package ="org.uddi.publication"/> </wsdl2java> +--> <!-- XMethods Delayed Quote Service from http://www.xmethods.net/detail.html?id=2 --> <wsdl2java url=" http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl" 1.16 +43 -86 xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java Index: Types.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/fromJava/Types.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- Types.java 8 Feb 2002 16:52:12 -0000 1.15 +++ Types.java 21 Feb 2002 18:51:23 -0000 1.16 @@ -57,10 +57,13 @@ package org.apache.axis.wsdl.fromJava; import org.apache.axis.Constants; +import org.apache.axis.AxisFault; import org.apache.axis.encoding.TypeMapping; import org.apache.axis.encoding.Serializer; import org.apache.axis.encoding.SerializerFactory; +import org.apache.axis.encoding.ser.BeanSerializerFactory; import org.apache.axis.utils.XMLUtils; +import org.apache.axis.utils.JavaUtils; import org.w3c.dom.Attr; import org.w3c.dom.Document; @@ -338,14 +341,7 @@ * @throws Exception */ public String writeType(Class type) throws Exception { - Serializer ser = null; - if (tm != null) { - SerializerFactory factory = (SerializerFactory)tm.getSerializer(type); - if (factory != null) { - ser = (Serializer)factory.getSerializerAs(Constants.AXIS_SAX); - } - } - + // Quick return if schema type if (isSimpleSchemaType(type)) return Constants.NSPREFIX_SCHEMA_XSD + ":" + @@ -354,7 +350,27 @@ return Constants.NSPREFIX_SOAP_ENC + ":" + getTypeQName(type).getLocalPart(); - // Write the namespace + // look up the serializer in the TypeMappingRegistry + Serializer ser = null; + SerializerFactory factory = null; + if (tm != null) { + factory = (SerializerFactory)tm.getSerializer(type); + } else { + factory = (SerializerFactory)defaultTM.getSerializer(type); + } + if (factory == null) { + factory = new BeanSerializerFactory(type, getTypeQName(type)); + } + if (factory != null) { + ser = (Serializer)factory.getSerializerAs(Constants.AXIS_SAX); + } + + // if we can't get a serializer, that is bad. + if (ser == null) + throw new AxisFault( + JavaUtils.getMessage("NoSerializer00", type.getName ())); + + // Write the namespace QName qName = writeTypeNamespace(type); // If an array the component type should be processed first @@ -397,10 +413,7 @@ if (isEnumClass(type)) { writeEnumType(qName, type); } else { - if (ser != null) - ser.writeSchema(this); - else - writeBeanClassType(qName, type); + ser.writeSchema(this); } } return prefixedName; @@ -508,83 +521,13 @@ } /** - * Write Bean Class Complex Type - * @param qname QName of type. - * @param type class of type - */ - public void writeBeanClassType(javax.wsdl.QName qName, Class cls) - throws Exception { - // ComplexType representation of bean class - Element complexType = docHolder.createElement("complexType"); - writeSchemaElement(qName, complexType); - complexType.setAttribute("name", qName.getLocalPart()); - - // See if there is a super class, stop if we hit a stop class - Element e = null; - Class superClass = cls.getSuperclass(); - if (superClass != null && - superClass != java.lang.Object.class && - (stopClasses == null || !stopClasses.contains(superClass.getName()))) { - // Write out the super class - String base = writeType(superClass); - Element complexContent = docHolder.createElement ("complexContent"); - complexType.appendChild(complexContent); - Element extension = docHolder.createElement("extension"); - complexContent.appendChild(extension); - extension.setAttribute("base", base); - e = extension; - } else { - e = complexType; - } - - // Add fields under all element - Element all = docHolder.createElement("all"); - e.appendChild(all); - - // Build a ClassRep that represents the bean class. This - // allows users to provide their own field mapping. - ClassRep clsRep = beanBuilder.build(cls); - - // Write out fields - Vector fields = clsRep.getFields(); - for (int i=0; i < fields.size(); i++) { - FieldRep field = (FieldRep) fields.elementAt(i); - - writeField(field.getName(), field.getType(), field.getIndexed(), all); - } - } - - /** - * write a schema representation of the given Class field and append it to the where Node * recurse on complex types - * @param fieldName name of the field - * @param fieldType type of the field - * @param isUnbounded causes maxOccurs="unbounded" if set - * @param where location for the generated schema node - * @throws Exception - */ - private void writeField(String fieldName, - Class fieldType, - boolean isUnbounded, - Element where) throws Exception { - String elementType = writeType(fieldType); - Element elem = createElement(fieldName, - elementType, - isNullable(fieldType), - where.getOwnerDocument()); - if (isUnbounded) { - elem.setAttribute("maxOccurs", "unbounded"); - } - where.appendChild(elem); - } - - /** * Create Element with a given name and type * @param elementName the name of the created element * @param elementType schema type representation of the element * @param nullable nullable attribute of the element * @return the created Element */ - private Element createElement(String elementName, + public Element createElement(String elementName, String elementType, boolean nullable, Document docHolder) { @@ -612,7 +555,7 @@ * @param type input Class * @return true if the type is a simple schema type */ - boolean isSimpleSchemaType(Class type) { + public boolean isSimpleSchemaType(Class type) { return (type == java.lang.String.class || type == java.lang.Boolean.TYPE || type == java.lang.Byte.TYPE || @@ -752,7 +695,7 @@ * @param type input Class * @return true if nullable */ - private boolean isNullable(Class type) { + public boolean isNullable(Class type) { if (type.isPrimitive() || (type.isArray() && type.getComponentType() == byte.class)) return false; @@ -783,6 +726,20 @@ doc.importNode(wsdlTypesElem, true), doc.getDocumentElement().getFirstChild()); } + } + + /** + * Return the list of classes that we should not emit WSDL for. + */ + public Vector getStopClasses() { + return stopClasses; + } + + /** + * Return the class rep that allows users to build their own beans + */ + public BuilderBeanClassRep getBeanBuilder() { + return beanBuilder; } /** 1.34 +19 -0 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.33 retrieving revision 1.34 diff -u -r1.33 -r1.34 --- SymbolTable.java 19 Feb 2002 20:55:00 -0000 1.33 +++ SymbolTable.java 21 Feb 2002 18:51:23 -0000 1.34 @@ -566,6 +566,25 @@ Constants.isSchemaXSD(nodeKind.getNamespaceURI())) { // we can no longer do .NET stuff and treat document as rpc style this.dotNet = false; + // Create symbol table entry for attribute type + QName refQName = Utils.getNodeTypeRefQName(node, "type"); + if (refQName == null) { + TypeEntry refType = getTypeEntry(refQName, false); + if (refType != null) { + // Not defined yet, add one + String baseName = btm.getBaseName(refQName); + if (baseName != null) { + BaseType bt = new BaseType(refQName); + bt.setIsReferenced(true); + symbolTablePut(bt); + } + else { + throw new IOException( + "Attribute type is not simple:" + refQName.toString()); + } + } + } + } } 1.10 +53 -0 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.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- SchemaUtils.java 15 Feb 2002 23:02:19 -0000 1.9 +++ SchemaUtils.java 21 Feb 2002 18:51:23 -0000 1.10 @@ -852,5 +852,58 @@ return null; } + /** + * Return the attribute names and types if any in the node + * The even indices are the element types (TypeEntry) and + * the odd indices are the corresponding names (Strings). + * + * Example: + * <complexType name="Person"> + * <sequence> + * <element minOccurs="1" maxOccurs="1" name="Age" type="double" /> + * <element minOccurs="1" maxOccurs="1" name="ID" type ="xsd:float" /> + * </sequence> + * <attribute name="Name" type="string" /> + * <attribute name="Male" type="boolean" /> + * </complexType> + * + */ + public static Vector getComplexElementAttributes(Node node, + SymbolTable symbolTable) + { + Vector v = null; // return value + + if (node == null) { + return null; + } + + // examine children of the node for <attribute> elements + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + QName nodeKind = Utils.getNodeQName(child); + if (nodeKind == null || + ! nodeKind.getLocalPart().equals("attribute")) + continue; + + // we have an attribute node + if (v == null) + v = new Vector(); + + // type + QName typeAttr = Utils.getNodeTypeRefQName(child, "type"); + TypeEntry type = symbolTable.getTypeEntry(typeAttr, false); + // name + QName name = Utils.getNodeNameQName(child); + // add type and name to vector, skip it if we couldn't parse it + // XXX - this may need to be revisited. + if (type != null && name != null) { + v.add(type); + v.add(name.getLocalPart()); + } + } + + return v; + } } 1.5 +9 -3 xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaTypeWriter.java Index: JavaTypeWriter.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaTypeWriter.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- JavaTypeWriter.java 23 Jan 2002 17:53:05 -0000 1.4 +++ JavaTypeWriter.java 21 Feb 2002 18:51:23 -0000 1.5 @@ -94,9 +94,15 @@ Vector v = SchemaUtils.getComplexElementTypesAndNames( node, symbolTable); if (v != null) { - typeWriter = new JavaComplexTypeWriter(emitter, type, v, - SchemaUtils.getComplexElementExtensionBase( - node, symbolTable)); + typeWriter = new + JavaComplexTypeWriter(emitter, + type, + v, + SchemaUtils.getComplexElementExtensionBase( + node, symbolTable), + SchemaUtils.getComplexElementAttributes( + node, + symbolTable)); } else { v = SchemaUtils.getEnumerationBaseAndValues( 1.7 +37 -3 xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaComplexTypeWriter.java Index: JavaComplexTypeWriter.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaComplexTypeWriter.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- JavaComplexTypeWriter.java 5 Feb 2002 21:53:49 -0000 1.6 +++ JavaComplexTypeWriter.java 21 Feb 2002 18:51:23 -0000 1.7 @@ -70,6 +70,7 @@ public class JavaComplexTypeWriter extends JavaWriter { private TypeEntry type; private Vector elements; + private Vector attributes; private TypeEntry extendType; /** @@ -81,11 +82,16 @@ */ protected JavaComplexTypeWriter( Emitter emitter, - TypeEntry type, Vector elements, TypeEntry extendType) { + TypeEntry type, + Vector elements, + TypeEntry extendType, + Vector attributes) + { super(emitter, type, "", "java", JavaUtils.getMessage("genType00"), "complexType"); this.type = type; this.elements = elements; + this.attributes = attributes; this.extendType = extendType; } // ctor @@ -109,12 +115,25 @@ names.add(((TypeEntry) elements.get(i)).getName()); names.add( Utils.xmlNameToJava((String) elements.get(i + 1))); } + // add the attributes to the names list (which will be bean elements too) + if (attributes != null) { + for (int i=0; i < attributes.size(); i+=2) { + names.add(((TypeEntry) attributes.get(i)).getName()); + names.add( Utils.xmlNameToJava((String) attributes.get(i + 1))); + } + } + pw.println("public class " + className + extendsText + " implements java.io.Serializable {"); for (int i = 0; i < names.size(); i += 2) { String variable = (String) names.get(i + 1); - pw.println(" private " + names.get(i) + " " + variable + ";"); + pw.print(" private " + names.get(i) + " " + variable + ";"); + // label the attribute fields. + if (i >= elements.size()) + pw.println(" // attribute"); + else + pw.println(); } pw.println(); @@ -163,7 +182,8 @@ // like the reasonable approach to take for collection types. // (It may be more efficient to handle this with an ArrayList...but // for the initial support it was easier to use an actual array.) - if (((TypeEntry)elements.elementAt(i)).getQName ().getLocalPart().indexOf("[")>0) { + if (i < elements.size() && + ((TypeEntry)elements.elementAt(i)).getQName ().getLocalPart().indexOf("[")>0) { String compName = typeName.substring(0, typeName.lastIndexOf("[")); @@ -191,6 +211,20 @@ pw.println(); } } + + // if we have attributes, create metadata function which returns the + // list of properties that are attributes instead of elements + if (attributes != null) { + pw.println(" public static java.util.Vector getAttributeElements() {"); + pw.println(" java.util.Vector v = new java.util.Vector ();"); + for (int i=0; i < attributes.size(); i+=2) { + pw.println(" v.add(\"" + Utils.xmlNameToJava ((String) attributes.get(i + 1)) + "\");"); + } + pw.println(" return v;"); + pw.println(" }"); + pw.println(); + } + pw.println("}"); pw.close(); } // writeOperation 1.57 +2 -1 xml-axis/java/src/org/apache/axis/utils/resources.properties Index: resources.properties =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/utils/resources.properties,v retrieving revision 1.56 retrieving revision 1.57 diff -u -r1.56 -r1.57 --- resources.properties 20 Feb 2002 17:17:35 -0000 1.56 +++ resources.properties 21 Feb 2002 18:51:23 -0000 1.57 @@ -643,7 +643,8 @@ literalTypePart00=Error: Message part {0} of operation or fault {1} is specified as a type and the soap:body use of binding "{2}" is literal. This WSDL is not currently supported. BadServiceName00=Error: Empty or missing service name -AttrNotSimpleType00=Attribute {0} is of type {1}, which is not a simple type +AttrNotSimpleType00=Bean attribute {0} is of type {1}, which is not a simple type +NoSerializer00=Unable to find serializer for type {0} optionTypeMapping00=indicate 1.1 or 1.2. The default is 1.2 (SOAP 1.2 JAX-RPC compliant) 1.6 +105 -1 xml-axis/java/src/org/apache/axis/encoding/ser/BeanSerializer.java Index: BeanSerializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/BeanSerializer.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- BeanSerializer.java 19 Feb 2002 20:50:46 -0000 1.5 +++ BeanSerializer.java 21 Feb 2002 18:51:23 -0000 1.6 @@ -71,6 +71,8 @@ import org.apache.axis.encoding.DeserializationContext; import org.apache.axis.encoding.DeserializerImpl; import org.apache.axis.InternalException; +import org.apache.axis.AxisFault; +import org.apache.axis.utils.JavaUtils; import org.apache.axis.wsdl.fromJava.ClassRep; import org.apache.axis.wsdl.fromJava.FieldRep; import org.apache.axis.wsdl.fromJava.Types; @@ -289,8 +291,110 @@ * @see org.apache.axis.wsdl.fromJava.Types */ public boolean writeSchema(Types types) throws Exception { - types.writeBeanClassType(types.getWsdlQName(xmlType), javaType); + + javax.wsdl.QName qName = types.getWsdlQName(xmlType); + + // ComplexType representation of bean class + Element complexType = types.createElement("complexType"); + types.writeSchemaElement(qName, complexType); + complexType.setAttribute("name", qName.getLocalPart()); + + // See if there is a super class, stop if we hit a stop class + Element e = null; + Class superClass = javaType.getSuperclass(); + Vector stopClasses = types.getStopClasses(); + if (superClass != null && + superClass != java.lang.Object.class && + (stopClasses == null || + !(stopClasses.contains(superClass.getName()))) ) { + // Write out the super class + String base = types.writeType(superClass); + Element complexContent = types.createElement ("complexContent"); + complexType.appendChild(complexContent); + Element extension = types.createElement("extension"); + complexContent.appendChild(extension); + extension.setAttribute("base", base); + e = extension; + } else { + e = complexType; + } + + // Add fields under all element + Element all = types.createElement("all"); + e.appendChild(all); + + // Build a ClassRep that represents the bean class. This + // allows users to provide their own field mapping. + ClassRep clsRep = types.getBeanBuilder().build(javaType); + + // Write out fields + Vector fields = clsRep.getFields(); + for (int i=0; i < fields.size(); i++) { + FieldRep field = (FieldRep) fields.elementAt(i); + + // if bean fields are attributes, write attribute element + if (beanAttributeNames.contains(field.getName())) + writeAttribute(types, field.getName(), + field.getType(), + complexType); + else + writeField(types, field.getName(), + field.getType(), + field.getIndexed(), + all); + } + // done return true; + } + + /** + * write a schema representation of the given Class field and append it to + * the where Node, recurse on complex types + * @param fieldName name of the field + * @param fieldType type of the field + * @param isUnbounded causes maxOccurs="unbounded" if set + * @param where location for the generated schema node + * @throws Exception + */ + private void writeField(Types types, String fieldName, + Class fieldType, + boolean isUnbounded, + Element where) throws Exception { + String elementType = types.writeType(fieldType); + Element elem = types.createElement(fieldName, + elementType, + types.isNullable(fieldType), + where.getOwnerDocument()); + if (isUnbounded) { + elem.setAttribute("maxOccurs", "unbounded"); + } + where.appendChild(elem); + } + + /** + * write aa attribute element and append it to the 'where' Node + * @param fieldName name of the field + * @param fieldType type of the field + * @param where location for the generated schema node + * @throws Exception + */ + private void writeAttribute(Types types, + String fieldName, + Class fieldType, + Element where) throws Exception { + + // Attribute must be a simple type. + if (!types.isSimpleSchemaType(fieldType)) + throw new AxisFault(JavaUtils.getMessage ("AttrNotSimpleType00", + fieldName, + fieldType.getName ())); + + String elementType = types.writeType(fieldType); + Element elem = types.createElement(fieldName, + elementType, + false, + where.getOwnerDocument()); + where.appendChild(elem); } /**