FileDocCategorySizeDatePackage
BeanSerializer.javaAPI DocApache Axis 1.427420Sat Apr 22 18:57:28 BST 2006org.apache.axis.encoding.ser

BeanSerializer

public class BeanSerializer extends Object implements Serializable, org.apache.axis.encoding.Serializer
General purpose serializer/deserializerFactory for an arbitrary java bean.
author
Sam Ruby
author
Rich Scheuerle
author
Tom Jordahl

Fields Summary
protected static Log
log
private static final QName
MUST_UNDERSTAND_QNAME
private static final Object[]
ZERO_ARGS
QName
xmlType
Class
javaType
protected org.apache.axis.utils.BeanPropertyDescriptor[]
propertyDescriptor
protected org.apache.axis.description.TypeDesc
typeDesc
Constructors Summary
public BeanSerializer(Class javaType, QName xmlType)


    // Construct BeanSerializer for the indicated class/qname
         
        this(javaType, xmlType, TypeDesc.getTypeDescForClass(javaType));
    
public BeanSerializer(Class javaType, QName xmlType, org.apache.axis.description.TypeDesc typeDesc)

        this(javaType, xmlType, typeDesc, null);

        if (typeDesc != null) {
            propertyDescriptor = typeDesc.getPropertyDescriptors();
        } else {
            propertyDescriptor = BeanUtils.getPd(javaType, null);
        }
    
public BeanSerializer(Class javaType, QName xmlType, org.apache.axis.description.TypeDesc typeDesc, org.apache.axis.utils.BeanPropertyDescriptor[] propertyDescriptor)

        this.xmlType = xmlType;
        this.javaType = javaType;
        this.typeDesc = typeDesc;
        this.propertyDescriptor = propertyDescriptor;
    
Methods Summary
public java.lang.StringgetMechanismType()

 return Constants.AXIS_SAX; 
protected org.xml.sax.AttributesgetObjectAttributes(java.lang.Object value, org.xml.sax.Attributes attributes, org.apache.axis.encoding.SerializationContext context)
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

param
value the object we are serializing
return
attributes for this element, null if none


        if (typeDesc == null || !typeDesc.hasAttributes())
            return attributes;

        AttributesImpl attrs;
        if (attributes == null) {
            attrs = new AttributesImpl();
        } else if (attributes instanceof AttributesImpl) {
            attrs = (AttributesImpl)attributes;
        } else {
            attrs = new AttributesImpl(attributes);
        }

        try {
            // 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;

                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("", propName);
                }

                if (propertyDescriptor[i].isReadable() &&
                    !propertyDescriptor[i].isIndexed()) {
                    // add to our attributes
                    Object propValue = propertyDescriptor[i].get(value);
                    // Convert true/false to 1/0 in case of soapenv:mustUnderstand
                    if (qname.equals(MUST_UNDERSTAND_QNAME)) {
                    	if (propValue.equals(Boolean.TRUE)) {
                                propValue = "1";
                    	} else if (propValue.equals(Boolean.FALSE)) {
                    		propValue = "0";
                    	}
                    }
                    // If the property value does not exist, don't serialize
                    // the attribute.  In the future, the decision to serializer
                    // the attribute may be more sophisticated.  For example, don't
                    // serialize if the attribute matches the default value.
                    if (propValue != null) {
                        setAttributeProperty(propValue,
                                             qname,
                                             field.getXmlType(), 
                                             field.getJavaType(),
                                             attrs,
                                             context);
                    }
                }
            }
        } catch (Exception e) {
            // no attributes
            return attrs;
        }

        return attrs;
    
public voidserialize(javax.xml.namespace.QName name, org.xml.sax.Attributes attributes, java.lang.Object value, org.apache.axis.encoding.SerializationContext context)
Serialize a bean. Done simply by serializing each bean property.

param
name is the element name
param
attributes are the attributes...serialize is free to add more.
param
value is the value
param
context is the SerializationContext

        // 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, context);

        // Get the encoding style
        boolean isEncoded = context.isEncoded();

        // check whether we have and xsd:any namespace="##any" type
        boolean suppressElement = !isEncoded &&
                                  name.getNamespaceURI().equals("") &&
                                  name.getLocalPart().equals("any");

        if (!suppressElement)
            context.startElement(name, beanAttrs);

        // check whether the array is converted to ArrayOfT shema type    
        if (value != null && value.getClass().isArray()) {
           Object newVal = JavaUtils.convert(value, javaType); 
           if (newVal != null && javaType.isAssignableFrom(newVal.getClass())) {
               value = newVal; 
           }
        }
        try {
            // Serialize each property
            for (int i=0; i<propertyDescriptor.length; i++) {
                String propName = propertyDescriptor[i].getName();
                if (propName.equals("class"))
                    continue;
                QName qname = null;
                QName xmlType = null;
                Class javaType = propertyDescriptor[i].getType();

                boolean isOmittable = false;
                // isNillable default value depends on the field type
                boolean isNillable = Types.isNullable(javaType);
                // isArray
                boolean isArray = false;
                QName itemQName = 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;
                        }

                        ElementDesc element = (ElementDesc)field;

                        // If we're SOAP encoded, just use the local part,
                        // not the namespace.  Otherwise use the whole
                        // QName.
                        if (isEncoded) {
                            qname = new QName(element.getXmlName().getLocalPart());
                        } else {
                            qname = element.getXmlName();
                        }
                        isOmittable = element.isMinOccursZero();
                        isNillable = element.isNillable();
                        isArray = element.isMaxOccursUnbounded();
                        xmlType = element.getXmlType();
                        itemQName = element.getItemQName();
                        context.setItemQName(itemQName);
                    }
                }

                if (qname == null) {
                    qname = new QName(isEncoded ? "" : name.getNamespaceURI(),
                                      propName);
                }

                if (xmlType == null) {
                    // look up the type QName using the class
                    xmlType = context.getQNameForClass(javaType);
                }

                // Read the value from the property
                if (propertyDescriptor[i].isReadable()) {
                    if (itemQName != null ||
                            (!propertyDescriptor[i].isIndexed() && !isArray)) {
                        // Normal case: serialize the value
                        Object propValue =
                            propertyDescriptor[i].get(value);


                        if (propValue == null) {
                            // an element cannot be null if nillable property is set to
                            // "false" and the element cannot be omitted
                            if (!isNillable && !isOmittable) {
                                if (Number.class.isAssignableFrom(javaType)) {
                                    // If we have a null and it's a number, though,
                                    // we might turn it into the appropriate kind of 0.
                                    // TODO : Should be caching these constructors?
                                    try {
                                        Constructor constructor =
                                                javaType.getConstructor(
                                                        SimpleDeserializer.STRING_CLASS);
                                        propValue = constructor.newInstance(ZERO_ARGS);
                                    } catch (Exception e) {
                                        // If anything goes wrong here, oh well we tried.
                                    }
                                }

                                if (propValue == null) {
                                    throw new IOException(
                                            Messages.getMessage(
                                                    "nullNonNillableElement",
                                                    propName));
                                }
                            }

                            // if meta data says minOccurs=0, then we can skip
                            // it if its value is null and we aren't doing SOAP
                            // encoding.
                            if (isOmittable && !isEncoded) {
                                continue;
                            }
                        }

                        context.serialize(qname,
                                          null,
                                          propValue,
                                          xmlType, javaType);
                    } else {
                        // Collection of properties: serialize each one
                        int j=0;
                        while(j >= 0) {
                            Object propValue = null;
                            try {
                                propValue =
                                    propertyDescriptor[i].get(value, j);
                                j++;
                            } catch (Exception e) {
                                j = -1;
                            }
                            if (j >= 0) {
                                context.serialize(qname, null,
                                                  propValue, xmlType, propertyDescriptor[i].getType());
                            }
                        }
                    }
                }
            }

            BeanPropertyDescriptor anyDesc = typeDesc == null ? null :
                    typeDesc.getAnyDesc();
            if (anyDesc != null) {
                // If we have "extra" content here, it'll be an array
                // of MessageElements.  Serialize each one.
                Object anyVal = anyDesc.get(value);
                if (anyVal != null && anyVal instanceof MessageElement[]) {
                    MessageElement [] anyContent = (MessageElement[])anyVal;
                    for (int i = 0; i < anyContent.length; i++) {
                        MessageElement element = anyContent[i];
                        element.output(context);
                    }
                }
            }
        } catch (InvocationTargetException ite) {
            Throwable target = ite.getTargetException();
            log.error(Messages.getMessage("exception00"), target);
            throw new IOException(target.toString());
        } catch (Exception e) {
            log.error(Messages.getMessage("exception00"), e);
            throw new IOException(e.toString());
        }

        if (!suppressElement)
            context.endElement();
    
private voidsetAttributeProperty(java.lang.Object propValue, javax.xml.namespace.QName qname, javax.xml.namespace.QName xmlType, java.lang.Class javaType, org.xml.sax.helpers.AttributesImpl attrs, org.apache.axis.encoding.SerializationContext context)


        String namespace = qname.getNamespaceURI();
        String localName = qname.getLocalPart();

        // org.xml.sax.helpers.AttributesImpl JavaDoc says: "For the
        // sake of speed, this method does no checking to see if the
        // attribute is already in the list: that is the
        // responsibility of the application." check for the existence
        // of the attribute to avoid adding it more than once.
        if (attrs.getIndex(namespace, localName) != -1) {
            return;
        }

        String propString = context.getValueAsString(propValue, xmlType, javaType);

        attrs.addAttribute(namespace,
                           localName,
                           context.attributeQName2String(qname),
                           "CDATA",
                           propString);
    
protected voidwriteAttribute(org.apache.axis.wsdl.fromJava.Types types, java.lang.String fieldName, java.lang.Class fieldType, javax.xml.namespace.QName fieldXmlType, org.w3c.dom.Element where)
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


        // Attribute must be a simple type.
        if (!types.isAcceptableAsAttribute(fieldType)) {
            throw new AxisFault(Messages.getMessage("AttrNotSimpleType00",
                                                     fieldName,
                                                     fieldType.getName()));
        }
        Element elem = types.createAttributeElement(fieldName,
                                           fieldType, fieldXmlType,
                                           false,
                                           where.getOwnerDocument());
        where.appendChild(elem);
    
protected voidwriteField(org.apache.axis.wsdl.fromJava.Types types, java.lang.String fieldName, javax.xml.namespace.QName xmlType, java.lang.Class fieldType, boolean isUnbounded, boolean isOmittable, org.w3c.dom.Element where, boolean isAnonymous, javax.xml.namespace.QName itemQName)
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
xmlType the schema type of the field
param
fieldType type of the field
param
isUnbounded causes maxOccurs="unbounded" if set
param
where location for the generated schema node
param
itemQName
throws
Exception

        Element elem;
        String elementType = null;

        if (isAnonymous) {
            elem = types.
                    createElementWithAnonymousType(fieldName,
                                                   fieldType,
                                                   isOmittable,
                                                   where.getOwnerDocument());
        } else {
            if (!SchemaUtils.isSimpleSchemaType(xmlType) &&
                    Types.isArray(fieldType)) {
                xmlType = null;
            }

            if (itemQName != null &&
                    SchemaUtils.isSimpleSchemaType(xmlType) &&
                    Types.isArray(fieldType)) {
                xmlType = null;
            }

            QName typeQName = types.writeTypeAndSubTypeForPart(fieldType, xmlType);
            elementType = types.getQNameString(typeQName);

            if (elementType == null) {
                // If writeType returns null, then emit an anytype.
                QName anyQN = Constants.XSD_ANYTYPE;
                String prefix = types.getNamespaces().
                        getCreatePrefix(anyQN.getNamespaceURI());
                elementType = prefix + ":" + anyQN.getLocalPart();
            }

            // isNillable default value depends on the field type
            boolean isNillable = Types.isNullable(fieldType);
            if (typeDesc != null) {
                FieldDesc field = typeDesc.getFieldByName(fieldName);
                if (field != null && field.isElement()) {
                    isNillable = ((ElementDesc)field).isNillable();
                }
            }

            elem = types.createElement(fieldName,
                    elementType,
                    isNillable,
                    isOmittable,
                    where.getOwnerDocument());
        }

        if (isUnbounded) {
            elem.setAttribute("maxOccurs", "unbounded");
        }

        where.appendChild(elem);
    
public org.w3c.dom.ElementwriteSchema(java.lang.Class javaType, org.apache.axis.wsdl.fromJava.Types types)
Return XML schema for the specified type, suitable for insertion into the <types> element of a WSDL document, or underneath an <element> or <attribute> declaration.

param
javaType the Java Class we're writing out schema for
param
types the Java2WSDL Types object which holds the context for the WSDL being generated.
return
a type element containing a schema simpleType/complexType
see
org.apache.axis.wsdl.fromJava.Types


        // ComplexType representation of bean class
        Element complexType = types.createElement("complexType");

        // See if there is a super class, stop if we hit a stop class
        Element e = null;
        Class superClass = javaType.getSuperclass();
        BeanPropertyDescriptor[] superPd = null;
        List stopClasses = types.getStopClasses();
        if (superClass != null &&
                superClass != java.lang.Object.class &&
                superClass != java.lang.Exception.class &&
                superClass != java.lang.Throwable.class &&
                superClass != java.lang.RuntimeException.class &&
                superClass != java.rmi.RemoteException.class &&
                superClass != org.apache.axis.AxisFault.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;
            // Get the property descriptors for the super class
            TypeDesc superTypeDesc = TypeDesc.getTypeDescForClass(superClass);
            if (superTypeDesc != null) {
                superPd = superTypeDesc.getPropertyDescriptors();
            } else {
                superPd = BeanUtils.getPd(superClass, null);
            }
        } else {
            e = complexType;
        }

        // Add fields under sequence element.
        // Note: In most situations it would be okay
        // to put the fields under an all element.
        // However it is illegal schema to put an
        // element with minOccurs=0 or maxOccurs>1 underneath
        // an all element.  This is the reason why a sequence
        // element is used.
        Element all = types.createElement("sequence");
        e.appendChild(all);

        if (Modifier.isAbstract(javaType.getModifiers())) {
            complexType.setAttribute("abstract", "true");
        }

        // Serialize each property
        for (int i=0; i<propertyDescriptor.length; i++) {
            String propName = propertyDescriptor[i].getName();

            // Don't serializer properties named class
            boolean writeProperty = true;
            if (propName.equals("class")) {
                writeProperty = false;
            }

            // Don't serialize the property if it is present
            // in the super class property list
            if (superPd != null && writeProperty) {
                for (int j=0; j<superPd.length && writeProperty; j++) {
                    if (propName.equals(superPd[j].getName())) {
                        writeProperty = false;
                    }
                }
            }
            if (!writeProperty) {
                continue;
            }

            // 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) {
                Class fieldType = propertyDescriptor[i].getType();
                FieldDesc field = typeDesc.getFieldByName(propName);

                if (field != null) {
                    QName qname = field.getXmlName();
                    QName fieldXmlType = field.getXmlType();
                    boolean isAnonymous = fieldXmlType != null && fieldXmlType.getLocalPart().startsWith(">");

                    if (qname != null) {
                        // FIXME!
                        // Check to see if this is in the right namespace -
                        // if it's not, we need to use an <element ref="">
                        // to represent it!!!

                        // Use the default...
                        propName = qname.getLocalPart();
                    }
                    if (!field.isElement()) {
                        writeAttribute(types,
                                       propName,
                                       fieldType,
                                       fieldXmlType,
                                       complexType);
                    } else {
                        writeField(types,
                                   propName,
                                   fieldXmlType,
                                   fieldType,
                                   propertyDescriptor[i].isIndexed(),
                                   field.isMinOccursZero(),
                                   all, isAnonymous,
                                   ((ElementDesc)field).getItemQName());
                    }
                } else {
                    writeField(types,
                               propName,
                               null,
                               fieldType,
                               propertyDescriptor[i].isIndexed(), false, all, false, null);
                }
            } else {
                boolean done = false;
                if (propertyDescriptor[i] instanceof FieldPropertyDescriptor){
                    FieldPropertyDescriptor fpd = (FieldPropertyDescriptor) propertyDescriptor[i];
                    Class clazz = fpd.getField().getType();
                    if(types.getTypeQName(clazz)!=null) {
                        writeField(types,
                                   propName,
                                   null,
                                   clazz,
                                   false, false, all, false, null);
                   
                        done = true;
                    }
                }
                if(!done) {
                    writeField(types,
                               propName,
                               null,
                               propertyDescriptor[i].getType(),
                               propertyDescriptor[i].isIndexed(), false, all, false, null);
                }                    
                
            }
        }

        // done
        return complexType;