tomj        02/02/19 12:50:46

  Modified:    java/src/org/apache/axis/encoding/ser BeanSerializer.java
                        BeanDeserializer.java
  Log:
  First step to supporting <attribute> in schema types:
  
  Add support for bean properties which are attributes instead of element.
  
  If the bean has a static getAttributeElements() function, which returns a
  Vector of property names, we use this to serialize/deserialize those properties
  as attributes on the element.
  
  Revision  Changes    Path
  1.5       +107 -28   
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.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- BeanSerializer.java       19 Feb 2002 17:38:20 -0000      1.4
  +++ BeanSerializer.java       19 Feb 2002 20:50:46 -0000      1.5
  @@ -57,6 +57,7 @@
   
   import org.xml.sax.Attributes;
   import org.xml.sax.SAXException;
  +import org.xml.sax.helpers.AttributesImpl;
   
   import javax.xml.rpc.namespace.QName;
   import java.io.IOException;
  @@ -89,12 +90,14 @@
   
   import java.util.HashMap;
   import java.util.Vector;
  +import java.util.Iterator;
   
   /**
    * General purpose serializer/deserializerFactory for an arbitrary java bean.
    *
    * @author Sam Ruby <[EMAIL PROTECTED]>
    * @author Rich Scheuerle <[EMAIL PROTECTED]>
  + * @author Tom Jordahl <[EMAIL PROTECTED]>
    */
   public class BeanSerializer implements Serializer, Serializable {
   
  @@ -117,23 +120,25 @@
       QName xmlType;
       Class javaType;
   
  -    // Static Table to store pd[] keyed by class
  -    private static HashMap pdMap = new HashMap();
  +    private BeanPropertyDescriptor[] propertyDescriptor = null;
  +    private Vector beanAttributeNames = null;
  +    
   
       // Construct BeanSerializer for the indicated class/qname
       public BeanSerializer(Class javaType, QName xmlType) {
           this.xmlType = xmlType;
           this.javaType = javaType;
  +        propertyDescriptor = getPd(javaType);
  +        beanAttributeNames = getBeanAttributes(javaType);
       }
   
       // Construct BeanSerializer for the indicated class/qname and format
       public BeanSerializer(Class javaType, QName xmlType, short format) {
           this.xmlType = xmlType;
           this.javaType = javaType;
  -        if (format > FORCE_LOWER ||
  -            format < PROPERTY_NAME)
  -            format = PROPERTY_NAME;
  -        this.elementPropertyFormat = format;
  +        setElementPropertyFormat(format);
  +        propertyDescriptor = getPd(javaType);
  +        beanAttributeNames = getBeanAttributes(javaType);
       }
   
       /**
  @@ -147,32 +152,43 @@
                             Object value, SerializationContext context)
           throws IOException
       {
  -        // Get the property descriptors describing the bean properties
  -        BeanPropertyDescriptor[] pd = getPd(javaType);
  -
  -        context.startElement(name, attributes);
  +        boolean isSOAP_ENC = Constants.
  +                isSOAP_ENC(context.getMessageContext().getEncodingStyle());
  +        if (isSOAP_ENC) {
  +            // SOAP encoding doesn't allow attributes
  +            context.startElement(name, attributes);
  +        } else {
  +            // 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.startElement(name, beanAttrs);
  +        }
   
           try {
               // Serialize each property
  -            for (int i=0; i<pd.length; i++) {
  -                String propName = pd[i].getName();
  -                if (propName.equals("class")) continue;
  +            for (int i=0; i<propertyDescriptor.length; i++) {
  +                String propName = propertyDescriptor[i].getName();
  +                if (propName.equals("class")) 
  +                    continue;
  +                if (!isSOAP_ENC && beanAttributeNames.contains(propName)) 
  +                    continue;
                   propName = format(propName, elementPropertyFormat);
   
  -                Method readMethod = pd[i].getReadMethod();
  +                Method readMethod = propertyDescriptor[i].getReadMethod();
                   if (readMethod != null && readMethod.getParameterTypes().length == 
0) {
                       // Normal case: serialize the value
  -                    Object propValue = pd[i].getReadMethod().invoke(value,noArgs);
  +                    Object propValue = 
propertyDescriptor[i].getReadMethod().invoke(value,noArgs);
                       context.serialize(new QName("", propName), null,
                                         propValue,
  -                                      pd[i].getReadMethod().getReturnType());
  +                                      
propertyDescriptor[i].getReadMethod().getReturnType());
                   } else {
                       // Collection of properties: serialize each one
                       int j=0;
                       while(j >= 0) {
                           Object propValue = null;
                           try {
  -                            propValue = pd[i].getReadMethod().invoke(value,
  +                            propValue = 
propertyDescriptor[i].getReadMethod().invoke(value,
                                                                        new Object[] { 
new Integer(j) });
                               j++;
                           } catch (Exception e) {
  @@ -181,7 +197,7 @@
                           if (j >= 0) {
                               context.serialize(new QName("", propName), null,
                                                 propValue,
  -                                              
pd[i].getReadMethod().getReturnType());
  +                                              
propertyDescriptor[i].getReadMethod().getReturnType());
                           }
                       }
                   }
  @@ -195,23 +211,40 @@
       }
   
       /**
  -     * Get/Create a BeanPropertyDescriptor array for the indicated class.
  +     * Create a BeanPropertyDescriptor array for the indicated class.
        */
       static BeanPropertyDescriptor[] getPd(Class javaType) {
  -        BeanPropertyDescriptor[] pd = (BeanPropertyDescriptor[]) 
pdMap.get(javaType);
  -        if (pd == null) {
  -            try {
  -                PropertyDescriptor[] rawPd = 
Introspector.getBeanInfo(javaType).getPropertyDescriptors();
  -                pd = 
BeanPropertyDescriptor.processPropertyDescriptors(rawPd,javaType);
  -            } catch (Exception e) {
  -                // this should never happen
  -                throw new InternalException(e);
  -            }
  +        BeanPropertyDescriptor[] pd;
  +        try {
  +            PropertyDescriptor[] rawPd = 
Introspector.getBeanInfo(javaType).getPropertyDescriptors();
  +            pd = BeanPropertyDescriptor.processPropertyDescriptors(rawPd,javaType);
  +        } catch (Exception e) {
  +            // this should never happen
  +            throw new InternalException(e);
           }
           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 [] {});
  +            
  +            return (Vector) getAttributeElements.invoke(null, noArgs);
  +            
  +        } catch (Exception e) {
  +            return new Vector();  // empty vector
  +        }
  +    }
  +    
  +    
  +    /**
        * Get the format of the elements for the properties
        */
       public short getElementPropertyFormat() {
  @@ -260,4 +293,50 @@
           return true;
       }
   
  +    /**
  +     * 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
  +     * @param pd the properties of this class
  +     * @return attributes for this element, null if none
  +     */ 
  +    private Attributes getObjectAttributes(Object value,
  +                                           Attributes attributes) {
  +        
  +        if (beanAttributeNames.isEmpty())
  +            return attributes;
  +        
  +        AttributesImpl 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();
  +                // skip it if its not in the list
  +                if (!beanAttributeNames.contains(propName)) continue;
  +                if (propName.equals("class")) continue;
  +                propName = format(propName, elementPropertyFormat);
  +                
  +                Method readMethod = propertyDescriptor[i].getReadMethod();
  +                if (readMethod != null && 
  +                    readMethod.getParameterTypes().length == 0) {
  +                    // add to our attributes
  +                    Object propValue = propertyDescriptor[i].
  +                                        getReadMethod().invoke(value,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);
  +                }
  +            }
  +        } catch (Exception e) {
  +            // no attributes
  +            return attrs;
  +        }
  +        
  +        return attrs;
  +    }
   }
  
  
  
  1.4       +96 -12    
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.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BeanDeserializer.java     19 Feb 2002 17:38:20 -0000      1.3
  +++ BeanDeserializer.java     19 Feb 2002 20:50:46 -0000      1.4
  @@ -71,6 +71,8 @@
   import org.apache.axis.encoding.DeserializerImpl;
   import org.apache.axis.encoding.TypeMapping;
   import org.apache.axis.utils.JavaUtils;
  +import org.apache.axis.Constants;
  +
   import java.beans.IntrospectionException;
   
   import java.lang.reflect.Method;
  @@ -81,12 +83,15 @@
   import java.beans.PropertyDescriptor;
   import java.io.ObjectStreamField;
   import java.io.Serializable;
  +import java.util.Vector;
  +import java.util.HashMap;
   
   /**
    * General purpose deserializer for an arbitrary java bean.
    *
    * @author Sam Ruby <[EMAIL PROTECTED]>
    * @author Rich Scheuerle <[EMAIL PROTECTED]>
  + * @author Tom Jordahl <[EMAIL PROTECTED]>
    */
   public class BeanDeserializer extends DeserializerImpl implements Deserializer, 
Serializable  {
       static Log log =
  @@ -95,6 +100,7 @@
       QName xmlType;
       Class javaType;
       private BeanPropertyDescriptor[] pd = null;
  +    private HashMap propertyMap = new HashMap();
   
       // This counter is updated to deal with deserialize collection properties
       protected int collectionIndex = -1;
  @@ -103,9 +109,20 @@
       public BeanDeserializer(Class javaType, QName xmlType) {
           this.xmlType = xmlType;
           this.javaType = javaType;
  +        // Get a list of the bean properties
  +        this.pd = BeanSerializer.getPd(javaType);
  +        // loop through properties and grab the names for later
  +        for (int i = 0; i < pd.length; i++) {
  +            BeanPropertyDescriptor descriptor = pd[i];
  +            propertyMap.put(descriptor.getName(), descriptor);
  +        }
  +        // create a value
           try {
               value=javaType.newInstance();
  -        } catch (Exception e) {} 
  +        } catch (Exception e) {
  +            //throw new SAXException(e.toString());
  +        }
  +        
       }
   
       /**
  @@ -127,17 +144,6 @@
                                       DeserializationContext context)
           throws SAXException
       {
  -        // Get a list of the bean properties
  -        BeanPropertyDescriptor[] pd = BeanSerializer.getPd(javaType);
  -
  -        // create a value if there isn't one already...
  -        if (value==null) {
  -            try {
  -                value=javaType.newInstance();
  -            } catch (Exception e) {
  -                throw new SAXException(e.toString());
  -            }
  -        }
   
           // look for a field by this name.  Assumes the the number of
           // properties in a bean is (relatively) small, so uses a linear
  @@ -185,4 +191,82 @@
           throw new SAXException(
                   JavaUtils.getMessage("badElem00", javaType.getName(), localName));
       }
  +
  +    /**
  +     * Set the bean properties that correspond to element attributes.
  +     * 
  +     * This method is invoked after startElement when the element requires
  +     * deserialization (i.e. the element is not an href and the value is not nil.)
  +     * @param namespace is the namespace of the element
  +     * @param localName is the name of the element
  +     * @param qName is the prefixed qName of the element
  +     * @param attributes are the attributes on the element...used to get the type
  +     * @param context is the DeserializationContext
  +     */
  +    public void onStartElement(String namespace, String localName,
  +                               String qName, Attributes attributes,
  +                               DeserializationContext context)
  +            throws SAXException {
  +
  +        // No attributes are allowed for SOAP encoding
  +        if (Constants.isSOAP_ENC(context.getMessageContext().getEncodingStyle())) {
  +            return;
  +        }
  +        // get list of properties that are really attributes
  +        Vector beanAttributeNames = BeanSerializer.getBeanAttributes(javaType);
  +        
  +        // loop through the attributes and set bean properties that 
  +        // correspond to attributes
  +        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);
  +            
  +            // 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(
  +                            JavaUtils.getMessage("unregistered00", 
type.toString()));
  +                
  +                // 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()));
  +                
  +                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);
  +                    }
  +                }
  +                
  +            } // if
  +        } // attribute loop
  +
  +    } // onStartElement
  +
   }
  
  
  


Reply via email to