{
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));
}