gdaniels 02/03/07 21:04:54 Modified: java/src/org/apache/axis/encoding DeserializationContextImpl.java java/src/org/apache/axis/encoding/ser BaseSerializerFactory.java BeanDeserializer.java BeanSerializer.java SimpleDeserializer.java SimpleSerializer.java java/src/org/apache/axis/wsdl/toJava JavaComplexTypeWriter.java java/test/encoding AttributeBean.java TestAttributes.java Added: java/src/org/apache/axis/description AttributeDesc.java ElementDesc.java FieldDesc.java TypeDesc.java java/test/encoding SimpleBean.java Log: Implement structured type mapping metadata, part I. * Define two new classes, TypeDesc and FieldDesc, representing metadata about a Java<->XML mapping for a given type. FieldDesc maps a given Java field to/from a particular XML element OR attribute, and has two subclasses, ElementDesc and AttributeDesc. The subclasses may be created directly, the FieldDesc root may not. * Adjust the code in the BeanSerializer/Deserializer and SimpleSerializer/ Deserializer to look for a static "getTypeDesc()" method on classes to obtain metadata instead of looking for the old "getAttributeNames()" string array. * Edit the stub generator to emit the new metadata style. * Fix up the TestAttributes test to use the new metadata style, test more combinations of present + missing metadata, and also add a test for a SimpleType with an attribute. So what does this mean? The framework is now in place for much smoother data binding, and we can eventually move towards supporting an xdoclet-type Javadoc syntax for expressing these kinds of mappings. We now support attributes which are in other namespaces than the default. Next steps: Get the emitter doing the right thing for XML -> Java name mangling. In other words, if we have to change an XML name when writing a stub from WSDL, we should now be able to keep track of the original XML name and add it to the metadata instead of relying on the Java -> XML reverse name mangling to preserve fidelity. Get the WSDL emitted for attributes to look correct. I was a little too tired to finish this tonight. Attempt to refactor the BeanSerializer/SimpleSerializer and equiv. deserializers into a common family so they can share all the duplicated code that currently lives both places. Clean up a bit more. Revision Changes Path 1.1 xml-axis/java/src/org/apache/axis/description/AttributeDesc.java Index: AttributeDesc.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.axis.description; /** * An AttributeDesc is a FieldDesc for an Java field mapping to an * XML attribute * * @author Glen Daniels ([EMAIL PROTECTED]) */ public class AttributeDesc extends FieldDesc { public AttributeDesc() { super(false); } } 1.1 xml-axis/java/src/org/apache/axis/description/ElementDesc.java Index: ElementDesc.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.axis.description; /** * An AttributeDesc is a FieldDesc for an Java field mapping to an * XML element * * @author Glen Daniels ([EMAIL PROTECTED]) */ public class ElementDesc extends FieldDesc { public ElementDesc() { super(true); } } 1.1 xml-axis/java/src/org/apache/axis/description/FieldDesc.java Index: FieldDesc.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.axis.description; import javax.xml.rpc.namespace.QName; /** * FieldDescs are metadata objects which control the mapping of a given * Java field to/from XML. * * @author Glen Daniels ([EMAIL PROTECTED]) */ public class FieldDesc { /** The name of the Java field in question */ private String fieldName; /** The XML QName this field maps to */ private QName xmlName; /** The XML Type this field maps to/from */ private QName xmlType; /** An indication of whether this should be an element or an attribute */ // Q : should this be a boolean, or just "instanceof ElementDesc", etc. private boolean _isElement = true; /** * Can't construct the base class directly, must construct either an * ElementDesc or an AttributeDesc. */ protected FieldDesc(boolean isElement) { _isElement = isElement; } /** * Obtain the field name. */ public String getFieldName() { return fieldName; } /** * Set the field name. */ public void setFieldName(String fieldName) { this.fieldName = fieldName; } /** * Obtain the XML QName for this field */ public QName getXmlName() { return xmlName; } /** * Set the XML QName for this field */ public void setXmlName(QName xmlName) { this.xmlName = xmlName; } /** * Check if this is an element or an attribute. * * @return true if this is an ElementDesc, or false if an AttributeDesc */ public boolean isElement() { return _isElement; } } 1.1 xml-axis/java/src/org/apache/axis/description/TypeDesc.java Index: TypeDesc.java =================================================================== package org.apache.axis.description; import javax.xml.rpc.namespace.QName; import java.util.HashMap; import java.lang.reflect.Array; public class TypeDesc { private FieldDesc [] fields; private HashMap fieldNameMap = new HashMap(); /** Are there any fields which are serialized as attributes? */ private boolean _hasAttributes = false; public FieldDesc[] getFields() { return fields; } public void setFields(FieldDesc [] newFields) { fieldNameMap = new HashMap(); fields = newFields; _hasAttributes = false; for (int i = 0; i < newFields.length; i++) { FieldDesc field = newFields[i]; if (field.isElement()) { fieldNameMap.put(field.getFieldName(), field); } else { _hasAttributes = true; } } } public void addFieldDesc(FieldDesc field) { if (field == null) throw new NullPointerException(); int numFields = 0; if (fields != null) { numFields = fields.length; } FieldDesc [] newFields = new FieldDesc[numFields + 1]; if (fields != null) { System.arraycopy(fields, 0, newFields, 0, numFields); } newFields[numFields] = field; fields = newFields; // Keep track of the field by name for fast lookup fieldNameMap.put(field.getFieldName(), field); if (!_hasAttributes && !field.isElement()) _hasAttributes = true; } public QName getElementNameForField(String fieldName) { FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName); if (desc == null || !desc.isElement()) return null; return desc.getXmlName(); } public QName getAttributeNameForField(String fieldName) { FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName); if (desc == null || desc.isElement()) return null; return desc.getXmlName(); } public String getFieldNameForElement(QName qname) { for (int i = 0; i < fields.length; i++) { FieldDesc field = fields[i]; if (field.isElement() && qname.equals(field.getXmlName())) return field.getFieldName(); } return null; } public String getFieldNameForAttribute(QName qname) { String possibleMatch = null; for (int i = 0; i < fields.length; i++) { FieldDesc field = fields[i]; if (!field.isElement()) { // It's an attribute, so if we have a solid match, return // its name. if (qname.equals(field.getXmlName())) { return field.getFieldName(); } // Not a solid match, but it's still possible we might match // the default (i.e. QName("", fieldName)) if (qname.getNamespaceURI().equals("") && qname.getLocalPart().equals(field.getFieldName())) { possibleMatch = field.getFieldName(); } } } return possibleMatch; } public FieldDesc getFieldByName(String name) { return (FieldDesc)fieldNameMap.get(name); } public boolean hasAttributes() { return _hasAttributes; } } 1.15 +7 -6 xml-axis/java/src/org/apache/axis/encoding/DeserializationContextImpl.java Index: DeserializationContextImpl.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/DeserializationContextImpl.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- DeserializationContextImpl.java 6 Mar 2002 19:35:49 -0000 1.14 +++ DeserializationContextImpl.java 8 Mar 2002 05:04:54 -0000 1.15 @@ -315,6 +315,13 @@ { QName typeQName = null; + // Check for type + String type = Constants.getValue(attrs, Constants.URI_CURRENT_SCHEMA_XSI, "type"); + if (type != null) { + // Return the type attribute value converted to a QName + return getQNameFromString(type); + } + if (typeQName == null) { // If the element is a SOAP-ENC element, the name of the element is the type. @@ -351,12 +358,6 @@ if (typeQName != null) return typeQName; - // Check for type - String type = Constants.getValue(attrs, Constants.URI_CURRENT_SCHEMA_XSI, "type"); - if (type != null) { - // Return the type attribute value converted to a QName - return getQNameFromString(type); - } /* Removing this code for now - Glen 2/20/02 1.2 +2 -1 xml-axis/java/src/org/apache/axis/encoding/ser/BaseSerializerFactory.java Index: BaseSerializerFactory.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/BaseSerializerFactory.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- BaseSerializerFactory.java 26 Jan 2002 02:40:34 -0000 1.1 +++ BaseSerializerFactory.java 8 Mar 2002 05:04:54 -0000 1.2 @@ -127,7 +127,8 @@ } ser = (Serializer) serClassConstructor.newInstance(new Object[] {javaType, xmlType}); - } catch (Exception e) {} + } catch (Exception e) { + } } // If not successfull, try newInstance if (ser == null) { 1.8 +123 -99 xml-axis/java/src/org/apache/axis/encoding/ser/BeanDeserializer.java Index: BeanDeserializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/BeanDeserializer.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- BeanDeserializer.java 6 Mar 2002 19:35:49 -0000 1.7 +++ BeanDeserializer.java 8 Mar 2002 05:04:54 -0000 1.8 @@ -72,6 +72,7 @@ import org.apache.axis.encoding.TypeMapping; import org.apache.axis.utils.JavaUtils; import org.apache.axis.Constants; +import org.apache.axis.description.TypeDesc; import java.beans.IntrospectionException; @@ -102,6 +103,9 @@ Class javaType; private BeanPropertyDescriptor[] pd = null; private HashMap propertyMap = new HashMap(); + + /** Type metadata about this class for XML deserialization */ + private TypeDesc typeDesc = null; // This counter is updated to deal with deserialize collection properties protected int collectionIndex = -1; @@ -117,6 +121,18 @@ BeanPropertyDescriptor descriptor = pd[i]; propertyMap.put(descriptor.getName(), descriptor); } + + // Get the class' TypeDesc if it provides one + try { + Method getTypeDesc = + javaType.getMethod("getTypeDesc", + new Class [] {}); + // get string array + typeDesc = (TypeDesc)getTypeDesc.invoke(null, + BeanSerializer.noArgs); + } catch (Exception e) { + } + // create a value try { value=javaType.newInstance(); @@ -145,58 +161,74 @@ DeserializationContext context) throws SAXException { + BeanPropertyDescriptor propDesc = null; + + if (typeDesc != null) { + QName elemQName = new QName(namespace, localName); + String fieldName = typeDesc.getFieldNameForElement(elemQName); + propDesc = (BeanPropertyDescriptor)propertyMap.get(fieldName); + } - // look for a field by this name. Assumes the the number of - // properties in a bean is (relatively) small, so uses a linear - // search. Accept a property if it differs only by the - // capitalization of the first character. - String localNameUp = BeanSerializer.format(localName, BeanSerializer.FORCE_UPPER); - String localNameLo = BeanSerializer.format(localName, BeanSerializer.FORCE_LOWER); - String mangledName = JavaUtils.xmlNameToJava(localName); - for (int i=0; i<pd.length; i++) { - if (pd[i].getWriteMethod() == null ) continue ; - if (pd[i].getName().equals(localNameUp) || - pd[i].getName().equals(localNameLo) || - pd[i].getName().equals(mangledName)) { - - // Determine the QName for this child element. - // Look at the type attribute specified. If this fails, - // use the javaType of the property to get the type qname. - QName qn = context.getTypeFromAttributes(namespace, localName, attributes); - - // get the deserializer - Deserializer dSer = context.getDeserializerForType(qn); - - // If no deserializer, use the base DeserializerImpl. - // There may not be enough information yet to choose the - // specific deserializer. - if (dSer == null) { - dSer = new DeserializerImpl(); - // determine a default type for this child element - TypeMapping tm = context.getTypeMapping(); - Class type = pd[i].getType(); - dSer.setDefaultType(tm.getTypeQName(type)); - } - - - if (pd[i].getWriteMethod().getParameterTypes().length == 1) { - // Success! Register the target and deserializer. - collectionIndex = -1; - dSer.registerValueTarget(new BeanPropertyTarget(value, pd[i])); - return (SOAPHandler) dSer; - } else { - // Success! This is a collection of properties so use the index - collectionIndex++; - dSer.registerValueTarget(new BeanPropertyTarget(value, pd[i], collectionIndex)); - return (SOAPHandler) dSer; + if (propDesc == null) { + // look for a field by this name. Assumes the the number of + // properties in a bean is (relatively) small, so uses a linear + // search. Accept a property if it differs only by the + // capitalization of the first character. + String localNameUp = + BeanSerializer.format(localName, + BeanSerializer.FORCE_UPPER); + String localNameLo = + BeanSerializer.format(localName, + BeanSerializer.FORCE_LOWER); + String mangledName = JavaUtils.xmlNameToJava(localName); + for (int i=0; i<pd.length; i++) { + if (pd[i].getWriteMethod() == null ) continue ; + if (pd[i].getName().equals(localNameUp) || + pd[i].getName().equals(localNameLo) || + pd[i].getName().equals(mangledName)) { + propDesc = pd[i]; } - } } + + if (propDesc == null) { + // No such field + throw new SAXException( + JavaUtils.getMessage("badElem00", javaType.getName(), + localName)); + } - // No such field - throw new SAXException( - JavaUtils.getMessage("badElem00", javaType.getName(), localName)); + // Determine the QName for this child element. + // Look at the type attribute specified. If this fails, + // use the javaType of the property to get the type qname. + QName qn = context.getTypeFromAttributes(namespace, localName, attributes); + + // get the deserializer + Deserializer dSer = context.getDeserializerForType(qn); + + // If no deserializer, use the base DeserializerImpl. + // There may not be enough information yet to choose the + // specific deserializer. + if (dSer == null) { + dSer = new DeserializerImpl(); + // determine a default type for this child element + TypeMapping tm = context.getTypeMapping(); + Class type = propDesc.getType(); + dSer.setDefaultType(tm.getTypeQName(type)); + } + + if (propDesc.getWriteMethod().getParameterTypes().length == 1) { + // Success! Register the target and deserializer. + collectionIndex = -1; + dSer.registerValueTarget(new BeanPropertyTarget(value, propDesc)); + } else { + // Success! This is a collection of properties so use the index + collectionIndex++; + dSer.registerValueTarget(new BeanPropertyTarget(value, + propDesc, + collectionIndex)); + } + return (SOAPHandler)dSer; } /** @@ -215,69 +247,61 @@ DeserializationContext context) throws SAXException { - // get list of properties that are really attributes - Vector beanAttributeNames = BeanSerializer.getBeanAttributes(javaType); + if (typeDesc == null) + return; // loop through the attributes and set bean properties that // correspond to attributes - if (beanAttributeNames != null && - beanAttributeNames.size() > 0) { - for (int i=0; i < attributes.getLength(); i++) { - String attrName = attributes.getLocalName(i); - String attrNameUp = BeanSerializer.format(attrName, BeanSerializer.FORCE_UPPER); - String attrNameLo = BeanSerializer.format(attrName, BeanSerializer.FORCE_LOWER); - String mangledName = JavaUtils.xmlNameToJava(attrName); - - // See if the attribute is a beanAttribute name - if (!beanAttributeNames.contains(attrName) && - !beanAttributeNames.contains(attrNameUp) && - !beanAttributeNames.contains(attrNameLo)) - continue; - - // look for the attribute property - BeanPropertyDescriptor bpd = - (BeanPropertyDescriptor) propertyMap.get(attrNameUp); - if (bpd == null) - bpd = (BeanPropertyDescriptor) propertyMap.get(attrNameLo); - if (bpd == null) - bpd = (BeanPropertyDescriptor) propertyMap.get(mangledName); - if (bpd != null) { - if (bpd.getWriteMethod() == null ) continue ; - - // determine the QName for this child element - TypeMapping tm = context.getTypeMapping(); - Class type = bpd.getType(); - QName qn = tm.getTypeQName(type); - if (qn == null) - throw new SAXException( + for (int i=0; i < attributes.getLength(); i++) { + QName attrQName = new QName(attributes.getURI(i), + attributes.getLocalName(i)); + String fieldName = typeDesc.getFieldNameForAttribute(attrQName); + if (fieldName == null) + continue; + + String attrName = attributes.getLocalName(i); + String attrNameUp = BeanSerializer.format(attrName, BeanSerializer.FORCE_UPPER); + String attrNameLo = BeanSerializer.format(attrName, BeanSerializer.FORCE_LOWER); + String mangledName = JavaUtils.xmlNameToJava(attrName); + + // look for the attribute property + BeanPropertyDescriptor bpd = + (BeanPropertyDescriptor) propertyMap.get(fieldName); + if (bpd != null) { + if (bpd.getWriteMethod() == null ) continue ; + + // determine the QName for this child element + TypeMapping tm = context.getTypeMapping(); + Class type = bpd.getType(); + QName qn = tm.getTypeQName(type); + if (qn == null) + throw new SAXException( JavaUtils.getMessage("unregistered00", type.toString())); - // get the deserializer - Deserializer dSer = context.getDeserializerForType(qn); - if (dSer == null) - throw new SAXException( + // get the deserializer + Deserializer dSer = context.getDeserializerForType(qn); + if (dSer == null) + throw new SAXException( JavaUtils.getMessage("noDeser00", type.toString())); - if (! (dSer instanceof SimpleDeserializer)) - throw new SAXException( + if (! (dSer instanceof SimpleDeserializer)) + throw new SAXException( JavaUtils.getMessage("AttrNotSimpleType00", bpd.getName(), type.toString())); - if (bpd.getWriteMethod().getParameterTypes().length == 1) { - // Success! Create an object from the string and set - // it in the bean - try { - Object val = ((SimpleDeserializer)dSer). + if (bpd.getWriteMethod().getParameterTypes().length == 1) { + // Success! Create an object from the string and set + // it in the bean + try { + Object val = ((SimpleDeserializer)dSer). makeValue(attributes.getValue(i)); - bpd.getWriteMethod().invoke(value, new Object[] {val} ); - } catch (Exception e) { - throw new SAXException(e); - } + bpd.getWriteMethod().invoke(value, new Object[] {val} ); + } catch (Exception e) { + throw new SAXException(e); } + } - } // if - } // attribute loop - } // if attributes exist - } // onStartElement - + } // if + } // attribute loop + } } 1.14 +120 -48 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.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- BeanSerializer.java 6 Mar 2002 19:35:49 -0000 1.13 +++ BeanSerializer.java 8 Mar 2002 05:04:54 -0000 1.14 @@ -72,6 +72,8 @@ import org.apache.axis.encoding.DeserializerImpl; import org.apache.axis.InternalException; import org.apache.axis.AxisFault; +import org.apache.axis.description.TypeDesc; +import org.apache.axis.description.FieldDesc; import org.apache.axis.utils.JavaUtils; import org.apache.axis.wsdl.fromJava.ClassRep; import org.apache.axis.wsdl.fromJava.FieldRep; @@ -109,7 +111,7 @@ protected static Log log = LogFactory.getLog(BeanSerializer.class.getName()); - private static final Object[] noArgs = new Object[] {}; // For convenience + public static final Object[] noArgs = new Object[] {}; // For convenience // When serializing, the property element names passed over the wire // are the names of the properties (format=PROPERTY_NAME). @@ -126,7 +128,7 @@ Class javaType; private BeanPropertyDescriptor[] propertyDescriptor = null; - private Vector beanAttributeNames = null; + private TypeDesc typeDesc = null; // Construct BeanSerializer for the indicated class/qname @@ -134,16 +136,22 @@ this.xmlType = xmlType; this.javaType = javaType; propertyDescriptor = getPd(javaType); - beanAttributeNames = getBeanAttributes(javaType); + + // Get the class' TypeDesc if it provides one + try { + Method getTypeDesc = + javaType.getMethod("getTypeDesc", + new Class [] {}); + // get string array + typeDesc = (TypeDesc)getTypeDesc.invoke(null, noArgs); + } catch (Exception e) { + } } // Construct BeanSerializer for the indicated class/qname and format public BeanSerializer(Class javaType, QName xmlType, short format) { - this.xmlType = xmlType; - this.javaType = javaType; + this(javaType, xmlType); setElementPropertyFormat(format); - propertyDescriptor = getPd(javaType); - beanAttributeNames = getBeanAttributes(javaType); } /** @@ -159,10 +167,11 @@ { boolean isSOAP_ENC = Constants. isSOAP_ENC(context.getMessageContext().getEncodingStyle()); + // Check for meta-data in the bean that will tell us if any of the // properties are actually attributes, add those to the element // attribute list - Attributes beanAttrs = getObjectAttributes(value, attributes); + Attributes beanAttrs = getObjectAttributes(value, attributes, context); context.startElement(name, beanAttrs); try { @@ -171,16 +180,36 @@ String propName = propertyDescriptor[i].getName(); if (propName.equals("class")) continue; - //if (!isSOAP_ENC && beanAttributeNames.contains(propName)) - if (beanAttributeNames.contains(Utils.xmlNameToJava(propName))) - continue; - propName = format(propName, elementPropertyFormat); + QName qname = null; + + // If we have type metadata, check to see what we're doing + // with this field. If it's an attribute, skip it. If it's + // an element, use whatever qname is in there. If we can't + // find any of this info, use the default. + + if (typeDesc != null) { + FieldDesc field = typeDesc.getFieldByName(propName); + if (field != null) { + if (!field.isElement()) + continue; + + qname = field.getXmlName(); + } + } + + if (qname == null) { + // Use the default... + propName = format(propName, elementPropertyFormat); + qname = new QName("", propName); + } + Method readMethod = propertyDescriptor[i].getReadMethod(); if (readMethod != null && readMethod.getParameterTypes().length == 0) { // Normal case: serialize the value Object propValue = propertyDescriptor[i].getReadMethod().invoke(value,noArgs); - context.serialize(new QName("", propName), null, + context.serialize(qname, + null, propValue, propertyDescriptor[i].getReadMethod().getReturnType()); } else { @@ -196,7 +225,7 @@ j = -1; } if (j >= 0) { - context.serialize(new QName("", propName), null, + context.serialize(qname, null, propValue, propertyDescriptor[i].getReadMethod().getReturnType()); } @@ -225,29 +254,46 @@ } return pd; } - + /** * Return a list of properties in the bean which should be attributes */ - static Vector getBeanAttributes(Class javaType) { - // See if this object defined the 'getAttributeElements' function - // which returns a Vector of property names that are attributes - try { - Method getAttributeElements = - javaType.getMethod("getAttributeElements", - new Class [] {}); - // get string array - String[] array = (String[])getAttributeElements.invoke(null, noArgs); - - // convert it to a Vector - Vector v = new Vector(array.length); - for (int i = 0; i < array.length; i++) { - v.add(array[i]); + static Vector getBeanAttributes(Class javaType, TypeDesc typeDesc) { + Vector ret = new Vector(); + + if (typeDesc == null) { + // !!! Support old-style beanAttributeNames for now + + // See if this object defined the 'getAttributeElements' function + // which returns a Vector of property names that are attributes + try { + Method getAttributeElements = + javaType.getMethod("getAttributeElements", + new Class [] {}); + // get string array + String[] array = (String[])getAttributeElements.invoke(null, noArgs); + + // convert it to a Vector + ret = new Vector(array.length); + for (int i = 0; i < array.length; i++) { + ret.add(array[i]); + } + } catch (Exception e) { + ret.clear(); + } + } else { + FieldDesc [] fields = typeDesc.getFields(); + if (fields != null) { + for (int i = 0; i < fields.length; i++) { + FieldDesc field = fields[i]; + if (!field.isElement()) { + ret.add(field.getFieldName()); + } + } } - return v; - } catch (Exception e) { - return new Vector(); // empty vector } + + return ret; } @@ -342,17 +388,27 @@ Vector fields = clsRep.getFields(); for (int i=0; i < fields.size(); i++) { FieldRep field = (FieldRep) fields.elementAt(i); + + if (typeDesc != null) { + FieldDesc fieldDesc = typeDesc.getFieldByName(field.getName()); + if (fieldDesc != null) { + if (!fieldDesc.isElement()) { + // !!! Need to get the QName right, and can only + // pass strings??? + writeAttribute(types, field.getName(), + field.getType(), + complexType); + } else { + // MEN WORKING!!!! + } + return true; + } + } - // 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); + writeField(types, field.getName(), + field.getType(), + field.getIndexed(), + all); } // done return true; @@ -418,9 +474,10 @@ * @return attributes for this element, null if none */ private Attributes getObjectAttributes(Object value, - Attributes attributes) { + Attributes attributes, + SerializationContext context) { - if (beanAttributeNames.isEmpty()) + if (typeDesc == null || !typeDesc.hasAttributes()) return attributes; AttributesImpl attrs; @@ -436,10 +493,17 @@ String propName = propertyDescriptor[i].getName(); if (propName.equals("class")) continue; - // skip it if its not in the list - if (!beanAttributeNames.contains(Utils.xmlNameToJava(propName))) + + FieldDesc field = typeDesc.getFieldByName(propName); + // skip it if its not an attribute + if (field == null || field.isElement()) continue; - propName = format(propName, elementPropertyFormat); + + QName qname = field.getXmlName(); + if (qname == null) { + qname = new QName("", + format(propName, elementPropertyFormat)); + } Method readMethod = propertyDescriptor[i].getReadMethod(); if (readMethod != null && @@ -450,7 +514,15 @@ // NOTE: we will always set the attribute here to something, // which we may not want (i.e. if null, omit it) String propString = propValue != null ? propValue.toString() : ""; - attrs.addAttribute("", propName, propName, "CDATA", propString); + + String namespace = qname.getNamespaceURI(); + String localName = qname.getLocalPart(); + + attrs.addAttribute(namespace, + localName, + context.qName2String(qname), + "CDATA", + propString); } } } catch (Exception e) { 1.5 +66 -60 xml-axis/java/src/org/apache/axis/encoding/ser/SimpleDeserializer.java Index: SimpleDeserializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/SimpleDeserializer.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SimpleDeserializer.java 27 Feb 2002 19:19:44 -0000 1.4 +++ SimpleDeserializer.java 8 Mar 2002 05:04:54 -0000 1.5 @@ -59,12 +59,14 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Vector; import java.util.HashMap; import java.util.Set; import java.util.Iterator; import org.apache.axis.InternalException; +import org.apache.axis.description.TypeDesc; import org.apache.axis.message.SOAPHandler; import org.apache.axis.utils.JavaUtils; @@ -103,6 +105,8 @@ public QName xmlType; public Class javaType; + private TypeDesc typeDesc = null; + /** * The Deserializer is constructed with the xmlType and * javaType (which could be a java primitive like int.class) @@ -119,6 +123,17 @@ BeanPropertyDescriptor descriptor = pd[i]; propertyMap.put(descriptor.getName(), descriptor); } + + // Get the class' TypeDesc if it provides one + try { + Method getTypeDesc = + javaType.getMethod("getTypeDesc", + new Class [] {}); + // get string array + typeDesc = (TypeDesc)getTypeDesc.invoke(null, + BeanSerializer.noArgs); + } catch (Exception e) { + } } } @@ -251,76 +266,66 @@ throws SAXException { - // if this isn't a simpleType bean, wont have attributes - if (! SimpleType.class.isAssignableFrom(javaType)) + // If we have no metadata, we have no attributes. Q.E.D. + if (typeDesc == null) return; - // get list of properties that are really attributes - Vector beanAttributeNames = BeanSerializer.getBeanAttributes(javaType); - - // loop through the attributes and set bean properties that + // loop through the attributes and set bean properties that // correspond to attributes - if (beanAttributeNames != null && - beanAttributeNames.size() > 0) { - for (int i=0; i < attributes.getLength(); i++) { - String attrName = attributes.getLocalName(i); - String attrNameUp = BeanSerializer.format(attrName, BeanSerializer.FORCE_UPPER); - String attrNameLo = BeanSerializer.format(attrName, BeanSerializer.FORCE_LOWER); - String mangledName = JavaUtils.xmlNameToJava(attrName); - - // See if the attribute is a beanAttribute name - if (!beanAttributeNames.contains(attrName) && - !beanAttributeNames.contains(attrNameUp) && - !beanAttributeNames.contains(attrNameLo)) - continue; - - if (attributeMap == null) - attributeMap = new HashMap(); - - // look for the attribute property, save the name - attrName = attrNameUp; - BeanPropertyDescriptor bpd = - (BeanPropertyDescriptor) propertyMap.get(attrNameUp); - if (bpd == null) { - attrName = attrNameLo; - bpd = (BeanPropertyDescriptor) propertyMap.get(attrNameLo); - } - if (bpd == null) { - attrName = mangledName; - bpd = (BeanPropertyDescriptor) propertyMap.get(mangledName); - } - if (bpd != null) { - // determine the QName for this child element - TypeMapping tm = context.getTypeMapping(); - Class type = bpd.getType(); - QName qn = tm.getTypeQName(type); - if (qn == null) - throw new SAXException( + for (int i=0; i < attributes.getLength(); i++) { + QName attrQName = new QName(attributes.getURI(i), + attributes.getLocalName(i)); + String fieldName = typeDesc.getFieldNameForAttribute(attrQName); + if (fieldName == null) + continue; + + String attrName = attributes.getLocalName(i); + String attrNameUp = BeanSerializer.format(attrName, BeanSerializer.FORCE_UPPER); + String attrNameLo = BeanSerializer.format(attrName, BeanSerializer.FORCE_LOWER); + String mangledName = JavaUtils.xmlNameToJava(attrName); + + // look for the attribute property + BeanPropertyDescriptor bpd = + (BeanPropertyDescriptor) propertyMap.get(fieldName); + if (bpd != null) { + if (bpd.getWriteMethod() == null ) continue ; + + // determine the QName for this child element + TypeMapping tm = context.getTypeMapping(); + Class type = bpd.getType(); + QName qn = tm.getTypeQName(type); + if (qn == null) + throw new SAXException( JavaUtils.getMessage("unregistered00", type.toString())); - - // get the deserializer - Deserializer dSer = context.getDeserializerForType(qn); - if (dSer == null) - throw new SAXException( + + // get the deserializer + Deserializer dSer = context.getDeserializerForType(qn); + if (dSer == null) + throw new SAXException( JavaUtils.getMessage("noDeser00", type.toString())); - if (! (dSer instanceof SimpleDeserializer)) - throw new SAXException( - JavaUtils.getMessage("AttrNotSimpleType00", - bpd.getName(), - type.toString())); - - // Success! Store name, value in HashMap for later + if (! (dSer instanceof SimpleDeserializer)) + throw new SAXException( + JavaUtils.getMessage("AttrNotSimpleType00", + bpd.getName(), + type.toString())); + + if (bpd.getWriteMethod().getParameterTypes().length == 1) { + // Success! Create an object from the string and save + // it in our attribute map for later. + if (attributeMap == null) { + attributeMap = new HashMap(); + } try { Object val = ((SimpleDeserializer)dSer). makeValue(attributes.getValue(i)); - attributeMap.put(attrName, val); + attributeMap.put(fieldName, val); } catch (Exception e) { throw new SAXException(e); } - - } // if bpd != null - } // attribute loop - } // if attributes exist + } + + } // if + } // attribute loop } // onStartElement /** @@ -328,7 +333,8 @@ */ private void setSimpleTypeAttributes() throws SAXException { // if this isn't a simpleType bean, wont have attributes - if (! SimpleType.class.isAssignableFrom(javaType)) + if (! SimpleType.class.isAssignableFrom(javaType) || + attributeMap == null) return; // loop through map 1.5 +55 -23 xml-axis/java/src/org/apache/axis/encoding/ser/SimpleSerializer.java Index: SimpleSerializer.java =================================================================== RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/encoding/ser/SimpleSerializer.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SimpleSerializer.java 27 Feb 2002 23:46:32 -0000 1.4 +++ SimpleSerializer.java 8 Mar 2002 05:04:54 -0000 1.5 @@ -67,6 +67,8 @@ import org.apache.axis.Constants; import org.apache.axis.AxisFault; +import org.apache.axis.description.TypeDesc; +import org.apache.axis.description.FieldDesc; import org.apache.axis.wsdl.fromJava.Types; import org.apache.axis.wsdl.fromJava.ClassRep; import org.apache.axis.wsdl.fromJava.FieldRep; @@ -94,8 +96,8 @@ public Class javaType; private BeanPropertyDescriptor[] propertyDescriptor = null; - private Vector beanAttributeNames = null; - + private TypeDesc typeDesc = null; + public SimpleSerializer(Class javaType, QName xmlType) { this.xmlType = xmlType; this.javaType = javaType; @@ -103,7 +105,16 @@ if (SimpleType.class.isAssignableFrom(javaType)) { // get the bean properties and the list of attributes from the bean propertyDescriptor = BeanSerializer.getPd(javaType); - beanAttributeNames = BeanSerializer.getBeanAttributes(javaType); + // Get the class' TypeDesc if it provides one + try { + Method getTypeDesc = + javaType.getMethod("getTypeDesc", + new Class [] {}); + // get string array + typeDesc = (TypeDesc)getTypeDesc.invoke(null, + BeanSerializer.noArgs); + } catch (Exception e) { + } } } /** @@ -123,7 +134,7 @@ // get any attributes if (value instanceof SimpleType) - attributes = getObjectAttributes(value, attributes); + attributes = getObjectAttributes(value, attributes, context); context.startElement(name, attributes); if (value != null) { @@ -159,39 +170,55 @@ context.endElement(); } - private Attributes getObjectAttributes(Object value, Attributes attributes) { - - // if nothing, return - if (beanAttributeNames.isEmpty()) + private Attributes getObjectAttributes(Object value, + Attributes attributes, + SerializationContext context) { + if (typeDesc == null || !typeDesc.hasAttributes()) return attributes; - + AttributesImpl attrs; if (attributes != null) attrs = new AttributesImpl(attributes); else attrs = new AttributesImpl(); - + try { - // Find each property that is an attribute + // Find each property that is an attribute // and add it to our attribute list for (int i=0; i<propertyDescriptor.length; i++) { String propName = propertyDescriptor[i].getName(); if (propName.equals("class")) continue; - // skip it if its not in the list - if (!beanAttributeNames.contains(Utils.xmlNameToJava(propName))) + + FieldDesc field = typeDesc.getFieldByName(propName); + // skip it if its not an attribute + if (field == null || field.isElement()) continue; - + + QName qname = field.getXmlName(); + if (qname == null) { + qname = new QName("", Utils.xmlNameToJava(propName)); + } + Method readMethod = propertyDescriptor[i].getReadMethod(); - if (readMethod != null && - readMethod.getParameterTypes().length == 0) { + if (readMethod != null && + readMethod.getParameterTypes().length == 0) { // add to our attributes Object propValue = propertyDescriptor[i]. - getReadMethod().invoke(value, new Object[]{}); - // NOTE: we will always set the attribute here to something, + getReadMethod(). + invoke(value,BeanSerializer.noArgs); + // NOTE: we will always set the attribute here to something, // which we may not want (i.e. if null, omit it) String propString = propValue != null ? propValue.toString() : ""; - attrs.addAttribute("", propName, propName, "CDATA", propString); + + String namespace = qname.getNamespaceURI(); + String localName = qname.getLocalPart(); + + attrs.addAttribute(namespace, + localName, + context.qName2String(qname), + "CDATA", + propString); } } } catch (Exception e) { @@ -253,17 +280,22 @@ // allows users to provide their own field mapping. ClassRep clsRep = types.getBeanBuilder().build(javaType); - // Write out fields + // Write out fields (only attributes are allowed) + if (typeDesc == null || !typeDesc.hasAttributes()) + return true; + Vector fields = clsRep.getFields(); for (int i=0; i < fields.size(); i++) { FieldRep field = (FieldRep) fields.elementAt(i); String fieldName = field.getName(); - - // if bean fields are attributes, write attribute element - if (!beanAttributeNames.contains(fieldName)) { + + FieldDesc fieldDesc = typeDesc.getFieldByName(field.getName()); + if (fieldDesc == null || fieldDesc.isElement()) { + // Really, it's an error to have element descriptors in there! continue; } + // write attribute element Class fieldType = field.getType(); 1.15 +31 -6 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.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- JavaComplexTypeWriter.java 28 Feb 2002 19:19:23 -0000 1.14 +++ JavaComplexTypeWriter.java 8 Mar 2002 05:04:54 -0000 1.15 @@ -123,6 +123,15 @@ if (type.isSimpleType()) implementsText = ", org.apache.axis.encoding.SimpleType"; + // For now, do the imports only if we have attributes. This will + // need to happen for any mapping later. + if (attributes != null) { + pw.println("import org.apache.axis.description.FieldDesc;"); + pw.println("import org.apache.axis.description.TypeDesc;"); + pw.println("import org.apache.axis.description.AttributeDesc;"); + pw.println(); + } + pw.println("public class " + className + extendsText + " implements java.io.Serializable" + implementsText + " {"); @@ -223,20 +232,36 @@ // if we have attributes, create metadata function which returns the // list of properties that are attributes instead of elements + + // Glen 3/7/02 : This is now using the type metadata model which + // provides for arbitrary mapping of XML elements or attributes + // <-> Java fields. We need to generalize this to support element + // mappings as well, but right now this is just to keep the attribute + // mechanism working. + if (attributes != null) { - pw.println(" // List of fields that are XML attributes"); - pw.println(" private static java.lang.String[] _attrs = new String[] {"); + pw.println(" // Type metadata"); + pw.println(" private static org.apache.axis.description.TypeDesc typeDesc ="); + pw.println(" new org.apache.axis.description.TypeDesc();"); + pw.println(); + pw.println(" static {"); for (int i = 0; i < attributes.size(); i += 2) { - pw.println(" \"" + Utils.xmlNameToJava((String) attributes.get(i + 1)) + "\", "); + String fieldName = + Utils.xmlNameToJava((String) attributes.get(i + 1)); + pw.print(" "); + if (i == 0) pw.print("org.apache.axis.description.FieldDesc "); + pw.println("field = new org.apache.axis.description.AttributeDesc();"); + pw.println(" field.setFieldName(\"" + fieldName + "\");"); + pw.println(" typeDesc.addFieldDesc(field);"); } pw.println(" };"); pw.println(); pw.println(" /**"); - pw.println(" * Return list of bean field names that are attributes"); + pw.println(" * Return type metadata object"); pw.println(" */"); - pw.println(" public static java.lang.String[] getAttributeElements() {"); - pw.println(" return _attrs;"); + pw.println(" public static org.apache.axis.description.TypeDesc getTypeDesc() {"); + pw.println(" return typeDesc;"); pw.println(" }"); pw.println(); } 1.2 +52 -13 xml-axis/java/test/encoding/AttributeBean.java Index: AttributeBean.java =================================================================== RCS file: /home/cvs/xml-axis/java/test/encoding/AttributeBean.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- AttributeBean.java 25 Feb 2002 15:24:14 -0000 1.1 +++ AttributeBean.java 8 Mar 2002 05:04:54 -0000 1.2 @@ -53,6 +53,13 @@ * <http://www.apache.org/>. */ +import org.apache.axis.description.AttributeDesc; +import org.apache.axis.description.ElementDesc; +import org.apache.axis.description.FieldDesc; +import org.apache.axis.description.TypeDesc; + +import javax.xml.rpc.namespace.QName; + /** * Simple Java Bean with fields that should be serialized as attributes */ @@ -103,18 +110,50 @@ public void setMale(boolean male) { this.male = male; } - - // List of fields that are XML attributes - public static java.lang.String[] _attrs = new String[] { - "name", - "male", - }; - - /** - * Return list of bean field names that are attributes - */ - public static java.lang.String[] getAttributeElements() { - return _attrs; + + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof AttributeBean)) + return false; + AttributeBean other = (AttributeBean)obj; + if (other.getAge() != age) + return false; + if (other.getID() != iD) + return false; + if (other.getMale() != male) + return false; + if (name == null) + return other.getName() == null; + return name.equals(other.getName()); + } + + // Type metadata + private static TypeDesc typeDesc; + + static { + typeDesc = new TypeDesc(); + FieldDesc field; + + // An attribute with a specified QName + field = new AttributeDesc(); + field.setFieldName("name"); + field.setXmlName(new QName("foo", "nameAttr")); + typeDesc.addFieldDesc(field); + + // An attribute with a default QName + field = new AttributeDesc(); + field.setFieldName("male"); + typeDesc.addFieldDesc(field); + + // An element with a specified QName + field = new ElementDesc(); + field.setFieldName("age"); + field.setXmlName(new QName("foo", "ageElement")); + typeDesc.addFieldDesc(field); + } + + public static TypeDesc getTypeDesc() + { + return typeDesc; } - } 1.2 +83 -52 xml-axis/java/test/encoding/TestAttributes.java Index: TestAttributes.java =================================================================== RCS file: /home/cvs/xml-axis/java/test/encoding/TestAttributes.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- TestAttributes.java 25 Feb 2002 15:24:14 -0000 1.1 +++ TestAttributes.java 8 Mar 2002 05:04:54 -0000 1.2 @@ -8,9 +8,17 @@ import org.apache.axis.encoding.SerializationContextImpl; import org.apache.axis.encoding.TypeMappingRegistry; import org.apache.axis.encoding.TypeMapping; +import org.apache.axis.encoding.SimpleType; import org.apache.axis.encoding.ser.BeanSerializerFactory; import org.apache.axis.encoding.ser.BeanDeserializerFactory; +import org.apache.axis.encoding.ser.SimpleDeserializerFactory; +import org.apache.axis.encoding.ser.SimpleNonPrimitiveSerializerFactory; import org.apache.axis.Constants; +import org.apache.axis.Message; +import org.apache.axis.description.TypeDesc; +import org.apache.axis.description.FieldDesc; +import org.apache.axis.description.OperationDesc; +import org.apache.axis.description.ServiceDesc; import org.apache.axis.utils.XMLUtils; import org.apache.axis.client.Call; import org.apache.axis.message.RPCElement; @@ -25,6 +33,7 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.util.Vector; import AttributeBean; @@ -32,6 +41,7 @@ * Test the serialization of a bean with attributes * * @author Tom Jordahl ([EMAIL PROTECTED]) + * @author Glen Daniels ([EMAIL PROTECTED]) */ public class TestAttributes extends TestCase { static Log log = @@ -43,35 +53,17 @@ { TestAttributes tester = new TestAttributes("TestAttributes"); tester.testBean(); + tester.testSimpleType(); } public TestAttributes(String name) { super(name); } - static final String expectedXML = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + - "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + - " <SOAP-ENV:Body>\n" + - " <method1 xmlns=\"urn:myNamespace\">\n" + - " <struct name=\"James Bond\" male=\"true\">\n" + - " <ID>1.15</ID>\n" + - " <age>35</age>\n" + - " </struct>\n" + - " </method1>\n" + - " </SOAP-ENV:Body>\n" + - "</SOAP-ENV:Envelope>"; - public void testBean () throws Exception { MessageContext msgContext = new MessageContext(new AxisServer()); SOAPEnvelope msg = new SOAPEnvelope(); - // set no encoding (use=literal) - msgContext.setEncodingStyle(null); - // Don't serialize xsi:type attributes - msgContext.setProperty(Call.SEND_TYPE_ATTR, "false" ); - - // Create bean with data AttributeBean bean = new AttributeBean(); bean.setAge(35); @@ -93,8 +85,8 @@ TypeMappingRegistry reg = context.getTypeMappingRegistry(); TypeMapping tm = (TypeMapping) reg.createTypeMapping(); // The "" namespace is literal (no encoding). - tm.setSupportedNamespaces(new String[] {""}); - reg.register("", tm); + tm.setSupportedNamespaces(new String[] {Constants.URI_CURRENT_SOAP_ENC}); + reg.register(Constants.URI_CURRENT_SOAP_ENC, tm); QName beanQName = new QName("typeNS", "TheBean"); tm.register(AttributeBean.class, @@ -106,40 +98,79 @@ msg.output(context); // Get the XML as a string String msgString = stringWriter.toString(); - // verify results - assertEquals("Serialized bean and expected results don't match", - expectedXML, msgString); - + log.debug("---"); log.debug(msgString); log.debug("---"); -/* - TODO: This part of the test is wrong - - // Now feed the XML in to the deserializer - StringReader reader = new StringReader(msgString); - DeserializationContext dser = new DeserializationContextImpl( - new InputSource(reader), msgContext, org.apache.axis.Message.REQUEST); - - // deserialize it - dser.parse(); - - // get the results - SOAPEnvelope env = dser.getEnvelope(); - RPCElement rpcElem = (RPCElement)env.getFirstBody(); - RPCParam struct = rpcElem.getParam("struct"); - assertNotNull("No <struct> param", struct); - - Object obj = struct.getValue(); - System.out.println(obj.toString()); - AttributeBean val = (AttributeBean)struct.getValue(); - assertNotNull("No value for struct param", val); - - assertEquals("Bean and Val Age members are not equal", bean.getAge(), val.getAge()); - assertEquals("Bean and Val ID members are not equal",bean.getID(), bean.getID(), 1.15F); - assertEquals("Bean and Val boolean attributes are not equal",bean.getMale(), bean.getMale()); - assertEquals("Bean and Val name attributes are not equal",bean.getName(), bean.getName()); -*/ + + Message message = new Message(msgString); + message.setMessageContext(msgContext); + SOAPEnvelope env = message.getSOAPPart().getAsSOAPEnvelope(); + RPCElement rpcEl = (RPCElement)env.getFirstBody(); + Vector params = rpcEl.getParams(); + assertEquals("Wrong # of params in deserialized message!", + 1, + params.size()); + + Object obj = ((RPCParam)params.get(0)).getValue(); + assertTrue("Deserialized param not an AttributeBean!", + (obj instanceof AttributeBean)); + + AttributeBean deserBean = (AttributeBean)obj; + assertTrue("Deserialized bean not equal to expected values!", + (bean.equals(deserBean))); } + public void testSimpleType() throws Exception { + SimpleBean bean = new SimpleBean("test value"); + bean.temp = 85.0F; + + MessageContext msgContext = new MessageContext(new AxisServer()); + SOAPEnvelope msg = new SOAPEnvelope(); + + RPCParam arg = new RPCParam("", "simple", bean); + RPCElement body = new RPCElement("urn:myNamespace", "method1", new Object[]{ arg }); + msg.addBodyElement(body); + body.setEncodingStyle(null); + + StringWriter writer = new StringWriter(); + SerializationContext context = new SerializationContextImpl(writer, + msgContext); + context.setDoMultiRefs(false); + + // Create a TypeMapping and register the Bean serializer/deserializer + TypeMappingRegistry reg = context.getTypeMappingRegistry(); + TypeMapping tm = (TypeMapping) reg.createTypeMapping(); + // The "" namespace is literal (no encoding). + tm.setSupportedNamespaces(new String[] {Constants.URI_CURRENT_SOAP_ENC}); + reg.register(Constants.URI_CURRENT_SOAP_ENC, tm); + + QName beanQName = new QName("typeNS", "Bean"); + tm.register(SimpleBean.class, + beanQName, + new SimpleNonPrimitiveSerializerFactory(SimpleBean.class, beanQName), + new SimpleDeserializerFactory(SimpleBean.class, beanQName)); + + // Serialize the bean in to XML + msg.output(context); + // Get the XML as a string + String msgString = writer.toString(); + + Message message = new Message(msgString); + message.setMessageContext(msgContext); + SOAPEnvelope env = message.getSOAPPart().getAsSOAPEnvelope(); + RPCElement rpcEl = (RPCElement)env.getFirstBody(); + Vector params = rpcEl.getParams(); + assertEquals("Wrong # of params in deserialized message!", + 1, + params.size()); + + Object obj = ((RPCParam)params.get(0)).getValue(); + assertTrue("Deserialized param not a SimpleBean!", + (obj instanceof SimpleBean)); + + SimpleBean deserBean = (SimpleBean)obj; + assertTrue("Deserialized bean not equal to expected values!", + (bean.equals(deserBean))); + } } 1.1 xml-axis/java/test/encoding/SimpleBean.java Index: SimpleBean.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package test.encoding; import org.apache.axis.description.AttributeDesc; import org.apache.axis.description.FieldDesc; import org.apache.axis.description.TypeDesc; import org.apache.axis.encoding.SimpleType; import javax.xml.rpc.namespace.QName; /** * A simple type with attributes for testing */ public class SimpleBean implements SimpleType { public String value; // Our "actual" value public float temp; // An attribute private static TypeDesc typeDesc = new TypeDesc(); static { FieldDesc fd = new AttributeDesc(); fd.setFieldName("temp"); fd.setXmlName(new QName("foo", "temp")); typeDesc.addFieldDesc(fd); } public static TypeDesc getTypeDesc() { return typeDesc; } /** * String constructor */ public SimpleBean(String val) { value = val; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public float getTemp() { return temp; } public void setTemp(float temp) { this.temp = temp; } public String toString() { return value; } public boolean equals(Object obj) { if (obj == null || !(obj instanceof SimpleBean)) return false; SimpleBean other = (SimpleBean)obj; if (other.getTemp() != temp) { return false; } if (value == null) { return other.getValue() == null; } return value.equals(other.getValue()); } }