This is way cool!
Personally, I'd prefer an array rather than a Vector, so someone writing a bean from scratch could just do: public String [] attrs = new String [] { "attribute" }; public String [] getAttributeElements() { return attrs; } Easier to write than vec.add(), vec.add(), vec.add()... just my opinion. --Glen > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]] > Sent: Thursday, February 21, 2002 1:51 PM > To: [EMAIL PROTECTED] > Subject: cvs commit: xml-axis/java/src/org/apache/axis/encoding/ser > BeanSerializer.java > > > 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-qu > otes.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/Symbol > Table.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/Schema > Utils.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/JavaTy > peWriter.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/JavaComplexTypeW > riter.java > > Index: JavaComplexTypeWriter.java > =================================================================== > RCS file: > /home/cvs/xml-axis/java/src/org/apache/axis/wsdl/toJava/JavaCo > mplexTypeWriter.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().i > ndexOf("[")>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.pr > operties,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/BeanS > erializer.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); > } > > /** > > > >