/*
* Copyright 2001,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.encoding.ser;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import org.apache.axis.description.TypeDesc;
import org.apache.axis.encoding.DeserializationContext;
import org.apache.axis.encoding.Deserializer;
import org.apache.axis.encoding.SimpleType;
import org.apache.axis.encoding.TypeMapping;
import org.apache.axis.message.SOAPHandler;
import org.apache.axis.utils.BeanPropertyDescriptor;
import org.apache.axis.utils.Messages;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Deserializer for
* <xsd:simpleType ...>
* <xsd:list itemType="...">
* </xsd:simpleType>
* based on SimpleDeserializer
*
* @author Ias (iasandcb@tmax.co.kr)
*/
public class SimpleListDeserializer extends SimpleDeserializer {
StringBuffer val = new StringBuffer();
private Constructor constructor = null;
private Map propertyMap = null;
private HashMap attributeMap = null;
private DeserializationContext context = null;
public QName xmlType;
public Class javaType;
private TypeDesc typeDesc = null;
protected SimpleListDeserializer cacheStringDSer = null;
protected QName cacheXMLType = null;
/**
* The Deserializer is constructed with the xmlType and
* javaType (which could be a java primitive like int.class)
*/
public SimpleListDeserializer(Class javaType, QName xmlType) {
super (javaType, xmlType);
this.xmlType = xmlType;
this.javaType = javaType;
}
public SimpleListDeserializer(Class javaType, QName xmlType, TypeDesc typeDesc) {
super (javaType, xmlType, typeDesc);
this.xmlType = xmlType;
this.javaType = javaType;
this.typeDesc = typeDesc;
}
/**
* Reset deserializer for re-use
*/
public void reset() {
val.setLength(0); // Reset string buffer back to zero
attributeMap = null; // Remove attribute map
isNil = false; // Don't know if nil
isEnded = false; // Indicate the end of element not yet called
}
/**
* The Factory calls setConstructor.
*/
public void setConstructor(Constructor c)
{
constructor = c;
}
/**
* There should not be nested elements, so thow and exception if this occurs.
*/
public SOAPHandler onStartChild(String namespace,
String localName,
String prefix,
Attributes attributes,
DeserializationContext context)
throws SAXException
{
throw new SAXException(
Messages.getMessage("cantHandle00", "SimpleDeserializer"));
}
/**
* Append any characters received to the value. This method is defined
* by Deserializer.
*/
public void characters(char [] chars, int start, int end)
throws SAXException
{
val.append(chars, start, end);
}
/**
* Append any characters to the value. This method is defined by
* Deserializer.
*/
public void onEndElement(String namespace, String localName,
DeserializationContext context)
throws SAXException
{
if (isNil || val == null) {
value = null;
return;
}
try {
value = makeValue(val.toString());
} catch (InvocationTargetException ite) {
Throwable realException = ite.getTargetException();
if (realException instanceof Exception)
throw new SAXException((Exception)realException);
else
throw new SAXException(ite.getMessage());
} catch (Exception e) {
throw new SAXException(e);
}
// If this is a SimpleType, set attributes we have stashed away
setSimpleTypeAttributes();
}
/**
* Convert the string that has been accumulated into an Object. Subclasses
* may override this.
* @param source the serialized value to be deserialized
* @throws Exception any exception thrown by this method will be wrapped
*/
public Object makeValue(String source) throws Exception
{
// According to XML Schema Spec Part 0: Primer 2.3.1 - white space delimitor
StringTokenizer tokenizer = new StringTokenizer(source.trim());
int length = tokenizer.countTokens();
Object list = Array.newInstance(javaType, length);
for (int i = 0; i < length; i++) {
String token = tokenizer.nextToken();
Array.set(list, i, makeUnitValue(token));
}
return list;
}
private Object makeUnitValue(String source) throws Exception
{
// If the javaType is a boolean, except a number of different sources
if (javaType == boolean.class || javaType == Boolean.class) {
// This is a pretty lame test, but it is what the previous code did.
switch (source.charAt(0)) {
case '0': case 'f': case 'F':
return Boolean.FALSE;
case '1': case 't': case 'T':
return Boolean.TRUE;
default:
throw new NumberFormatException(
Messages.getMessage("badBool00"));
}
}
// If expecting a Float or a Double, need to accept some special cases.
if (javaType == float.class ||
javaType == java.lang.Float.class) {
if (source.equals("NaN")) {
return new Float(Float.NaN);
} else if (source.equals("INF")) {
return new Float(Float.POSITIVE_INFINITY);
} else if (source.equals("-INF")) {
return new Float(Float.NEGATIVE_INFINITY);
}
}
if (javaType == double.class ||
javaType == java.lang.Double.class) {
if (source.equals("NaN")) {
return new Double(Double.NaN);
} else if (source.equals("INF")) {
return new Double(Double.POSITIVE_INFINITY);
} else if (source.equals("-INF")) {
return new Double(Double.NEGATIVE_INFINITY);
}
}
if (javaType == QName.class) {
int colon = source.lastIndexOf(":");
String namespace = colon < 0 ? "" :
context.getNamespaceURI(source.substring(0, colon));
String localPart = colon < 0 ? source :
source.substring(colon + 1);
return new QName(namespace, localPart);
}
return constructor.newInstance(new Object [] { source });
}
/**
* 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 prefix is the prefix 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 prefix, Attributes attributes,
DeserializationContext context)
throws SAXException
{
this.context = context;
// If we have no metadata, we have no attributes. Q.E.D.
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;
// look for the attribute property
BeanPropertyDescriptor bpd =
(BeanPropertyDescriptor) propertyMap.get(fieldName);
if (bpd != null) {
if (!bpd.isWriteable() || bpd.isIndexed() ) 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(
Messages.getMessage("unregistered00", type.toString()));
// get the deserializer
Deserializer dSer = context.getDeserializerForType(qn);
if (dSer == null)
throw new SAXException(
Messages.getMessage("noDeser00", type.toString()));
if (! (dSer instanceof SimpleListDeserializer))
throw new SAXException(
Messages.getMessage("AttrNotSimpleType00",
bpd.getName(),
type.toString()));
// 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 = ((SimpleListDeserializer)dSer).
makeValue(attributes.getValue(i));
attributeMap.put(fieldName, val);
} catch (Exception e) {
throw new SAXException(e);
}
} // if
} // attribute loop
} // onStartElement
/**
* Process any attributes we may have encountered (in onStartElement)
*/
private void setSimpleTypeAttributes() throws SAXException {
// if this isn't a simpleType bean, wont have attributes
if (! SimpleType.class.isAssignableFrom(javaType) ||
attributeMap == null)
return;
// loop through map
Set entries = attributeMap.entrySet();
for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String name = (String) entry.getKey();
Object val = entry.getValue();
BeanPropertyDescriptor bpd =
(BeanPropertyDescriptor) propertyMap.get(name);
if (!bpd.isWriteable() || bpd.isIndexed()) continue;
try {
bpd.set(value, val );
} catch (Exception e) {
throw new SAXException(e);
}
}
}
}
|