ArraySerializerpublic class ArraySerializer extends Object implements org.apache.axis.encoding.SerializerAn ArraySerializer handles serializing of arrays.
Some code borrowed from ApacheSOAP - thanks to Matt Duftler! |
Fields Summary |
---|
QName | xmlType | Class | javaType | QName | componentType | QName | componentQName | protected static Log | log |
Constructors Summary |
---|
public ArraySerializer(Class javaType, QName xmlType)Constructor
this.javaType = javaType;
this.xmlType = xmlType;
| public ArraySerializer(Class javaType, QName xmlType, QName componentType)Constructor
Special constructor that takes the component type of the array.
this(javaType, xmlType);
this.componentType = componentType;
| public ArraySerializer(Class javaType, QName xmlType, QName componentType, QName componentQName)Constructor
Special constructor that takes the component type and QName of the array.
this(javaType, xmlType, componentType);
this.componentQName = componentQName;
|
Methods Summary |
---|
private static java.lang.Class | getComponentType(java.lang.Class clazz)
if (clazz.isArray())
{
return clazz.getComponentType();
}
else if (java.util.Collection.class.isAssignableFrom(clazz))
{
return Object.class;
}
else
{
return null;
}
| public java.lang.String | getMechanismType() return Constants.AXIS_SAX;
| private static boolean | isArray(java.lang.Class clazz)
return clazz.isArray() || java.util.Collection.class.isAssignableFrom(clazz);
| public void | serialize(javax.xml.namespace.QName name, org.xml.sax.Attributes attributes, java.lang.Object value, org.apache.axis.encoding.SerializationContext context)Serialize an element that is an array.
if (value == null)
throw new IOException(Messages.getMessage("cantDoNullArray00"));
MessageContext msgContext = context.getMessageContext();
SchemaVersion schema = SchemaVersion.SCHEMA_2001;
SOAPConstants soap = SOAPConstants.SOAP11_CONSTANTS;
boolean encoded = context.isEncoded();
if (msgContext != null) {
schema = msgContext.getSchemaVersion();
soap = msgContext.getSOAPConstants();
}
Class cls = value.getClass();
Collection list = null;
if (!cls.isArray()) {
if (!(value instanceof Collection)) {
throw new IOException(
Messages.getMessage("cantSerialize00", cls.getName()));
}
list = (Collection)value;
}
// Get the componentType of the array/list
Class componentClass;
if (list == null) {
componentClass = cls.getComponentType();
} else {
componentClass = Object.class;
}
// Get the QName of the componentType
// if it wasn't passed in from the constructor
QName componentTypeQName = this.componentType;
// Check to see if componentType is also an array.
// If so, set the componentType to the most nested non-array
// componentType. Increase the dims string by "[]"
// each time through the loop.
// Note from Rich Scheuerle:
// This won't handle Lists of Lists or
// arrays of Lists....only arrays of arrays.
String dims = "";
if (componentTypeQName != null) {
// if we have a Type QName at this point,
// this is because ArraySerializer has been instanciated with it
TypeMapping tm = context.getTypeMapping();
SerializerFactory factory = (SerializerFactory) tm.getSerializer(
componentClass, componentTypeQName);
while (componentClass.isArray()
&& factory instanceof ArraySerializerFactory) {
ArraySerializerFactory asf = (ArraySerializerFactory) factory;
componentClass = componentClass.getComponentType();
QName componentType = null;
if (asf.getComponentType() != null) {
componentType = asf.getComponentType();
if(encoded) {
componentTypeQName = componentType;
}
}
// update factory with the new values
factory = (SerializerFactory) tm.getSerializer(componentClass,
componentType);
if (soap == SOAPConstants.SOAP12_CONSTANTS)
dims += "* ";
else
dims += "[]";
}
} else {
// compatibility mode
while (componentClass.isArray()) {
componentClass = componentClass.getComponentType();
if (soap == SOAPConstants.SOAP12_CONSTANTS)
dims += "* ";
else
dims += "[]";
}
}
// Try the current XML type from the context
if (componentTypeQName == null) {
componentTypeQName = context.getCurrentXMLType();
if (componentTypeQName != null) {
if ((componentTypeQName.equals(xmlType) ||
componentTypeQName.equals(Constants.XSD_ANYTYPE) ||
componentTypeQName.equals(soap.getArrayType()))) {
componentTypeQName = null;
}
}
}
if (componentTypeQName == null) {
componentTypeQName = context.getItemType();
}
// Then check the type mapping for the class
if (componentTypeQName == null) {
componentTypeQName = context.getQNameForClass(componentClass);
}
// If still not found, look at the super classes
if (componentTypeQName == null) {
Class searchCls = componentClass;
while(searchCls != null && componentTypeQName == null) {
searchCls = searchCls.getSuperclass();
componentTypeQName = context.getQNameForClass(searchCls);
}
if (componentTypeQName != null) {
componentClass = searchCls;
}
}
// Still can't find it? Throw an error.
if (componentTypeQName == null) {
throw new IOException(
Messages.getMessage("noType00", componentClass.getName()));
}
int len = (list == null) ? Array.getLength(value) : list.size();
String arrayType = "";
int dim2Len = -1;
if (encoded) {
if (soap == SOAPConstants.SOAP12_CONSTANTS) {
arrayType = dims + len;
} else {
arrayType = dims + "[" + len + "]";
}
// Discover whether array can be serialized directly as a two-dimensional
// array (i.e. arrayType=int[2,3]) versus an array of arrays.
// Benefits:
// - Less text passed on the wire.
// - Easier to read wire format
// - Tests the deserialization of multi-dimensional arrays.
// Drawbacks:
// - Is not safe! It is possible that the arrays are multiply
// referenced. Transforming into a 2-dim array will cause the
// multi-referenced information to be lost. Plus there is no
// way to determine whether the arrays are multi-referenced.
// - .NET currently (Dec 2002) does not support 2D SOAP-encoded arrays
//
// OLD Comment as to why this was ENABLED:
// It is necessary for
// interoperability (echo2DStringArray). It is 'safe' for now
// because Axis treats arrays as non multi-ref (see the note
// in SerializationContext.isPrimitive(...) )
// More complicated processing is necessary for 3-dim arrays, etc.
//
// Axis 1.1 - December 2002
// Turned this OFF because Microsoft .NET can not deserialize
// multi-dimensional SOAP-encoded arrays, and this interopability
// is pretty high visibility. Make it a global configuration parameter:
// <parameter name="enable2DArrayEncoding" value="true"/> (tomj)
//
// Check the message context to see if we should turn 2D processing ON
// Default is OFF
boolean enable2Dim = false;
// Vidyanand : added this check
if( msgContext != null ) {
enable2Dim = JavaUtils.isTrueExplicitly(msgContext.getProperty(
AxisEngine.PROP_TWOD_ARRAY_ENCODING));
}
if (enable2Dim && !dims.equals("")) {
if (cls.isArray() && len > 0) {
boolean okay = true;
// Make sure all of the component arrays are the same size
for (int i=0; i < len && okay; i++) {
Object elementValue = Array.get(value, i);
if (elementValue == null)
okay = false;
else if (dim2Len < 0) {
dim2Len = Array.getLength(elementValue);
if (dim2Len <= 0) {
okay = false;
}
} else if (dim2Len != Array.getLength(elementValue)) {
okay = false;
}
}
// Update the arrayType to use mult-dim array encoding
if (okay) {
dims = dims.substring(0, dims.length()-2);
if (soap == SOAPConstants.SOAP12_CONSTANTS)
arrayType = dims + len + " " + dim2Len;
else
arrayType = dims + "[" + len + "," + dim2Len + "]";
} else {
dim2Len = -1;
}
}
}
}
// Need to distinguish if this is array processing for an
// actual schema array or for a maxOccurs usage.
// For the maxOccurs case, the currentXMLType of the context is
// the same as the componentTypeQName.
QName itemQName = context.getItemQName();
boolean maxOccursUsage = !encoded && itemQName == null &&
componentTypeQName.equals(context.getCurrentXMLType());
if (encoded) {
AttributesImpl attrs;
if (attributes == null) {
attrs = new AttributesImpl();
} else if (attributes instanceof AttributesImpl) {
attrs = (AttributesImpl)attributes;
} else {
attrs = new AttributesImpl(attributes);
}
String compType = context.attributeQName2String(componentTypeQName);
if (attrs.getIndex(soap.getEncodingURI(), soap.getAttrItemType()) == -1) {
String encprefix =
context.getPrefixForURI(soap.getEncodingURI());
if (soap != SOAPConstants.SOAP12_CONSTANTS) {
compType = compType + arrayType;
attrs.addAttribute(soap.getEncodingURI(),
soap.getAttrItemType(),
encprefix + ":arrayType",
"CDATA",
compType);
} else {
attrs.addAttribute(soap.getEncodingURI(),
soap.getAttrItemType(),
encprefix + ":itemType",
"CDATA",
compType);
attrs.addAttribute(soap.getEncodingURI(),
"arraySize",
encprefix + ":arraySize",
"CDATA",
arrayType);
}
}
// Force type to be SOAP_ARRAY for all array serialization.
//
// There are two choices here:
// Force the type to type=SOAP_ARRAY
// Pros: More interop test successes.
// Cons: Since we have specific type information it
// is more correct to use it. Plus the specific
// type information may be important on the
// server side to disambiguate overloaded operations.
// Use the specific type information:
// Pros: The specific type information is more correct
// and may be useful for operation overloading.
// Cons: More interop test failures (as of 2/6/2002).
//
String qname =
context.getPrefixForURI(schema.getXsiURI(),
"xsi") + ":type";
QName soapArray;
if (soap == SOAPConstants.SOAP12_CONSTANTS) {
soapArray = Constants.SOAP_ARRAY12;
} else {
soapArray = Constants.SOAP_ARRAY;
}
int typeI = attrs.getIndex(schema.getXsiURI(),
"type");
if (typeI != -1) {
attrs.setAttribute(typeI,
schema.getXsiURI(),
"type",
qname,
"CDATA",
context.qName2String(soapArray));
} else {
attrs.addAttribute(schema.getXsiURI(),
"type",
qname,
"CDATA",
context.qName2String(soapArray));
}
attributes = attrs;
}
// For the maxOccurs case, each item is named with the QName
// we got in the arguments. For normal array case, we write an element with
// that QName, and then serialize each item as <item>
QName elementName = name;
Attributes serializeAttr = attributes;
if (!maxOccursUsage) {
serializeAttr = null; // since we are putting them here
context.startElement(name, attributes);
if (itemQName != null)
elementName = itemQName;
else if(componentQName != null)
elementName = componentQName;
}
if (dim2Len < 0) {
// Normal case, serialize each array element
if (list == null) {
for (int index = 0; index < len; index++) {
Object aValue = Array.get(value, index);
// Serialize the element.
context.serialize(elementName,
(serializeAttr == null ?
serializeAttr : new AttributesImpl(serializeAttr)),
aValue,
componentTypeQName, componentClass); // prefered type QName
}
} else {
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object aValue = iterator.next();
// Serialize the element.
context.serialize(elementName,
(serializeAttr == null ?
serializeAttr : new AttributesImpl(serializeAttr)),
aValue,
componentTypeQName, componentClass); // prefered type QName
}
}
} else {
// Serialize as a 2 dimensional array
for (int index = 0; index < len; index++) {
for (int index2 = 0; index2 < dim2Len; index2++) {
Object aValue = Array.get(Array.get(value, index), index2);
context.serialize(elementName, null, aValue, componentTypeQName, componentClass);
}
}
}
if (!maxOccursUsage)
context.endElement();
| public org.w3c.dom.Element | writeSchema(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.
boolean encoded = true;
MessageContext mc = MessageContext.getCurrentContext();
if (mc != null) {
encoded = mc.isEncoded();
} else {
encoded = types.getServiceDesc().getUse() == Use.ENCODED;
}
if (!encoded) {
Class cType = Object.class;
if (javaType.isArray()) {
cType = javaType.getComponentType();
}
String typeName = types.writeType(cType);
return types.createLiteralArrayElement(typeName, null);
}
// If an array the component type should be processed first
String componentTypeName = null;
Class componentType = null;
if (isArray(javaType)) {
String dimString = "[]";
componentType = getComponentType(javaType);
while (isArray(componentType)) {
dimString += "[]";
componentType = getComponentType(componentType);
}
types.writeType(componentType,null);
componentTypeName =
types.getQNameString(types.getTypeQName(componentType)) +
dimString;
}
// Use Types helper method to actually create the complexType
return types.createArrayElement(componentTypeName);
|
|