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
+
}