BeanDeserializerpublic class BeanDeserializer extends org.apache.axis.encoding.DeserializerImpl implements SerializableGeneral purpose deserializer for an arbitrary java bean. |
Fields Summary |
---|
protected static Log | log | private final CharArrayWriter | val | QName | xmlType | Class | javaType | protected Map | propertyMap | protected QName | prevQName | protected Constructor | constructorToUseConstructor if no default constructor | protected org.apache.axis.encoding.Target | constructorTargetConstructor Target object to use (if constructorToUse != null) | protected org.apache.axis.description.TypeDesc | typeDescType metadata about this class for XML deserialization | protected int | collectionIndex | protected SimpleDeserializer | cacheStringDSer | protected QName | cacheXMLType |
Constructors Summary |
---|
public BeanDeserializer(Class javaType, QName xmlType)
// Construct BeanSerializer for the indicated class/qname
this(javaType, xmlType, TypeDesc.getTypeDescForClass(javaType));
| public BeanDeserializer(Class javaType, QName xmlType, org.apache.axis.description.TypeDesc typeDesc)
this(javaType, xmlType, typeDesc,
BeanDeserializerFactory.getProperties(javaType, typeDesc));
| public BeanDeserializer(Class javaType, QName xmlType, org.apache.axis.description.TypeDesc typeDesc, Map propertyMap)
this.xmlType = xmlType;
this.javaType = javaType;
this.typeDesc = typeDesc;
this.propertyMap = propertyMap;
// create a value
try {
value=javaType.newInstance();
} catch (Exception e) {
// Don't process the exception at this point.
// This is defered until the call to startElement
// which will throw the exception.
}
|
Methods Summary |
---|
public void | characters(char[] chars, int start, int end)
val.write(chars, start, end);
| public org.apache.axis.utils.BeanPropertyDescriptor | getAnyPropertyDesc()Get a BeanPropertyDescriptor which indicates where we should
put extensibility elements (i.e. XML which falls under the
auspices of an <xsd:any> declaration in the schema)
if (typeDesc == null)
return null;
return typeDesc.getAnyDesc();
| protected org.apache.axis.encoding.Deserializer | getDeserializer(javax.xml.namespace.QName xmlType, java.lang.Class javaType, java.lang.String href, org.apache.axis.encoding.DeserializationContext context)Get the Deserializer for the attribute or child element.
if (javaType.isArray()) {
context.setDestinationClass(javaType);
}
// See if we have a cached deserializer
if (cacheStringDSer != null) {
if (String.class.equals(javaType) &&
href == null &&
(cacheXMLType == null && xmlType == null ||
cacheXMLType != null && cacheXMLType.equals(xmlType))) {
cacheStringDSer.reset();
return cacheStringDSer;
}
}
Deserializer dSer = null;
if (xmlType != null && href == null) {
// Use the xmlType to get the deserializer.
dSer = context.getDeserializerForType(xmlType);
} else {
// If the xmlType is not set, get a default xmlType
TypeMapping tm = context.getTypeMapping();
QName defaultXMLType = tm.getTypeQName(javaType);
// If there is not href, then get the deserializer
// using the javaType and default XMLType,
// If there is an href, the create the generic
// DeserializerImpl and set its default type (the
// default type is used if the href'd element does
// not have an xsi:type.
if (href == null) {
dSer = context.getDeserializer(javaType, defaultXMLType);
} else {
dSer = new DeserializerImpl();
context.setDestinationClass(javaType);
dSer.setDefaultType(defaultXMLType);
}
}
if (javaType.equals(String.class) &&
dSer instanceof SimpleDeserializer) {
cacheStringDSer = (SimpleDeserializer) dSer;
cacheXMLType = xmlType;
}
return dSer;
| protected void | handleMixedContent()
BeanPropertyDescriptor propDesc = getAnyPropertyDesc();
if (propDesc == null || val.size() == 0) {
return;
}
String textValue = val.toString().trim();
val.reset();
if (textValue.length() == 0) {
return;
}
try {
MessageElement[] curElements = (MessageElement[]) propDesc.get(value);
int length = 0;
if (curElements != null) {
length = curElements.length;
}
MessageElement[] newElements = new MessageElement[length + 1];
if (curElements != null) {
System.arraycopy(curElements, 0,
newElements, 0, length);
}
MessageElement thisEl = new MessageElement(new org.apache.axis.message.Text(textValue));
newElements[length] = thisEl;
propDesc.set(value, newElements);
} catch (Exception e) {
throw new SAXException(e);
}
| public void | onEndElement(java.lang.String namespace, java.lang.String localName, org.apache.axis.encoding.DeserializationContext context)
handleMixedContent();
| public org.apache.axis.message.SOAPHandler | onStartChild(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, org.apache.axis.encoding.DeserializationContext context)Deserializer interface called on each child element encountered in
the XML stream.
handleMixedContent();
BeanPropertyDescriptor propDesc = null;
FieldDesc fieldDesc = null;
SOAPConstants soapConstants = context.getSOAPConstants();
String encodingStyle = context.getEncodingStyle();
boolean isEncoded = Constants.isSOAP_ENC(encodingStyle);
QName elemQName = new QName(namespace, localName);
// The collectionIndex needs to be reset for Beans with multiple arrays
if ((prevQName == null) || (!prevQName.equals(elemQName))) {
collectionIndex = -1;
}
boolean isArray = false;
QName itemQName = null;
if (typeDesc != null) {
// Lookup the name appropriately (assuming an unqualified
// name for SOAP encoding, using the namespace otherwise)
String fieldName = typeDesc.getFieldNameForElement(elemQName,
isEncoded);
propDesc = (BeanPropertyDescriptor)propertyMap.get(fieldName);
fieldDesc = typeDesc.getFieldByName(fieldName);
if (fieldDesc != null) {
ElementDesc element = (ElementDesc)fieldDesc;
isArray = element.isMaxOccursUnbounded();
itemQName = element.getItemQName();
}
}
if (propDesc == null) {
// look for a field by this name.
propDesc = (BeanPropertyDescriptor) propertyMap.get(localName);
}
// try and see if this is an xsd:any namespace="##any" element before
// reporting a problem
if (propDesc == null ||
(((prevQName != null) && prevQName.equals(elemQName) &&
!(propDesc.isIndexed()||isArray)
&& getAnyPropertyDesc() != null ))) {
// try to put unknown elements into a SOAPElement property, if
// appropriate
prevQName = elemQName;
propDesc = getAnyPropertyDesc();
if (propDesc != null) {
try {
MessageElement [] curElements = (MessageElement[])propDesc.get(value);
int length = 0;
if (curElements != null) {
length = curElements.length;
}
MessageElement [] newElements = new MessageElement[length + 1];
if (curElements != null) {
System.arraycopy(curElements, 0,
newElements, 0, length);
}
MessageElement thisEl = context.getCurElement();
newElements[length] = thisEl;
propDesc.set(value, newElements);
// if this is the first pass through the MessageContexts
// make sure that the correct any element is set,
// that is the child of the current MessageElement, however
// on the first pass this child has not been set yet, so
// defer it to the child SOAPHandler
if (!localName.equals(thisEl.getName())) {
return new SOAPHandler(newElements, length);
}
return new SOAPHandler();
} catch (Exception e) {
throw new SAXException(e);
}
}
}
if (propDesc == null) {
// No such field
throw new SAXException(
Messages.getMessage("badElem00", javaType.getName(),
localName));
}
prevQName = elemQName;
// Get the child's xsi:type if available
QName childXMLType = context.getTypeFromAttributes(namespace,
localName,
attributes);
String href = attributes.getValue(soapConstants.getAttrHref());
Class fieldType = propDesc.getType();
// If no xsi:type or href, check the meta-data for the field
if (childXMLType == null && fieldDesc != null && href == null) {
childXMLType = fieldDesc.getXmlType();
if (itemQName != null) {
// This is actually a wrapped literal array and should be
// deserialized with the ArrayDeserializer
childXMLType = Constants.SOAP_ARRAY;
fieldType = propDesc.getActualType();
} else {
childXMLType = fieldDesc.getXmlType();
}
}
// Get Deserializer for child, default to using DeserializerImpl
Deserializer dSer = getDeserializer(childXMLType,
fieldType,
href,
context);
// It is an error if the dSer is not found - the only case where we
// wouldn't have a deserializer at this point is when we're trying
// to deserialize something we have no clue about (no good xsi:type,
// no good metadata).
if (dSer == null) {
dSer = context.getDeserializerForClass(propDesc.getType());
}
// Fastpath nil checks...
if (context.isNil(attributes)) {
if (propDesc != null && (propDesc.isIndexed()||isArray)) {
if (!((dSer != null) && (dSer instanceof ArrayDeserializer))) {
collectionIndex++;
dSer.registerValueTarget(new BeanPropertyTarget(value,
propDesc, collectionIndex));
addChildDeserializer(dSer);
return (SOAPHandler)dSer;
}
}
return null;
}
if (dSer == null) {
throw new SAXException(Messages.getMessage("noDeser00",
childXMLType.toString()));
}
if (constructorToUse != null) {
if (constructorTarget == null) {
constructorTarget = new ConstructorTarget(constructorToUse, this);
}
dSer.registerValueTarget(constructorTarget);
} else if (propDesc.isWriteable()) {
// If this is an indexed property, and the deserializer we found
// was NOT the ArrayDeserializer, this is a non-SOAP array:
// <bean>
// <field>value1</field>
// <field>value2</field>
// ...
// In this case, we want to use the collectionIndex and make sure
// the deserialized value for the child element goes into the
// right place in the collection.
// Register value target
if ((itemQName != null || propDesc.isIndexed() || isArray) && !(dSer instanceof ArrayDeserializer)) {
collectionIndex++;
dSer.registerValueTarget(new BeanPropertyTarget(value,
propDesc, collectionIndex));
} else {
// If we're here, the element maps to a single field value,
// whether that be a "basic" type or an array, so use the
// normal (non-indexed) BeanPropertyTarget form.
collectionIndex = -1;
dSer.registerValueTarget(new BeanPropertyTarget(value,
propDesc));
}
}
// Let the framework know that we need this deserializer to complete
// for the bean to complete.
addChildDeserializer(dSer);
return (SOAPHandler)dSer;
| public void | onStartElement(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, org.apache.axis.encoding.DeserializationContext context)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.)
// The value should have been created or assigned already.
// This code may no longer be needed.
if (value == null && constructorToUse == null) {
// create a value
try {
value=javaType.newInstance();
} catch (Exception e) {
throw new SAXException(Messages.getMessage("cantCreateBean00",
javaType.getName(),
e.toString()));
}
}
// If no type description meta data, there are no attributes,
// so we are done.
if (typeDesc == null)
return;
// loop through the attributes and set bean properties that
// correspond to attributes
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;
FieldDesc fieldDesc = typeDesc.getFieldByName(fieldName);
// look for the attribute property
BeanPropertyDescriptor bpd =
(BeanPropertyDescriptor) propertyMap.get(fieldName);
if (bpd != null) {
if (constructorToUse == null) {
// check only if default constructor
if (!bpd.isWriteable() || bpd.isIndexed()) continue ;
}
// Get the Deserializer for the attribute
Deserializer dSer = getDeserializer(fieldDesc.getXmlType(),
bpd.getType(),
null,
context);
if (dSer == null) {
dSer = context.getDeserializerForClass(bpd.getType());
// The java type is an array, but the context didn't
// know that we are an attribute. Better stick with
// simple types..
if (dSer instanceof ArrayDeserializer)
{
SimpleListDeserializerFactory factory =
new SimpleListDeserializerFactory(bpd.getType(),
fieldDesc.getXmlType());
dSer = (Deserializer)
factory.getDeserializerAs(dSer.getMechanismType());
}
}
if (dSer == null)
throw new SAXException(
Messages.getMessage("unregistered00",
bpd.getType().toString()));
if (! (dSer instanceof SimpleDeserializer))
throw new SAXException(
Messages.getMessage("AttrNotSimpleType00",
bpd.getName(),
bpd.getType().toString()));
// Success! Create an object from the string and set
// it in the bean
try {
dSer.onStartElement(namespace, localName, prefix,
attributes, context);
Object val = ((SimpleDeserializer)dSer).
makeValue(attributes.getValue(i));
if (constructorToUse == null) {
bpd.set(value, val);
} else {
// add value for our constructor
if (constructorTarget == null) {
constructorTarget = new ConstructorTarget(constructorToUse, this);
}
constructorTarget.set(val);
}
} catch (Exception e) {
throw new SAXException(e);
}
} // if
} // attribute loop
| public void | startElement(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, org.apache.axis.encoding.DeserializationContext context)startElement
The ONLY reason that this method is overridden is so that
the object value can be set or a reasonable exception is thrown
indicating that the object cannot be created. This is done
at this point so that it occurs BEFORE href/id processing.
// Create the bean object if it was not already
// created in the constructor.
if (value == null) {
try {
value=javaType.newInstance();
} catch (Exception e) {
// Use first found constructor.
// Note : the right way is to use XML mapping information
// for example JSR 109's constructor-parameter-order
Constructor[] constructors = javaType.getConstructors();
if (constructors.length > 0) {
constructorToUse = constructors[0];
}
// Failed to create an object if no constructor
if (constructorToUse == null) {
throw new SAXException(Messages.getMessage("cantCreateBean00",
javaType.getName(),
e.toString()));
}
}
}
// Invoke super.startElement to do the href/id processing.
super.startElement(namespace, localName,
prefix, attributes, context);
|
|