FileDocCategorySizeDatePackage
TypeMappingImpl.javaAPI DocApache Axis 1.428906Sat Apr 22 18:57:28 BST 2006org.apache.axis.encoding

TypeMappingImpl

public class TypeMappingImpl extends Object implements Serializable

This is the implementation of the axis TypeMapping interface (which extends the JAX-RPC TypeMapping interface).

A TypeMapping is obtained from the singleton TypeMappingRegistry using the namespace of the webservice. The TypeMapping contains the tuples {Java type, SerializerFactory, DeserializerFactory, Type QName)

So if you have a Web Service with the namespace "XYZ", you call the TypeMappingRegistry.getTypeMapping("XYZ").

The wsdl in your web service will use a number of types. The tuple information for each of these will be accessed via the TypeMapping.

Because every web service uses the soap, schema, wsdl primitives, we could pre-populate the TypeMapping with these standard tuples. Instead, if the namespace/class matches is not found in the TypeMapping the request is delegated to the Default TypeMapping or another TypeMapping

author
Rich Scheuerle (scheu@us.ibm.com)

Fields Summary
protected static Log
log
public static boolean
dotnet_soapenc_bugfix
Work around a .NET bug with soap encoded types. This is a static property of the type mapping that will cause the class to ignore SOAPENC types when looking up QNames of java types. See getTypeQNameExact().
private HashMap
qName2Pair
private HashMap
class2Pair
private HashMap
pair2SF
private HashMap
pair2DF
private ArrayList
namespaces
protected Boolean
doAutoTypes
Constructors Summary
public TypeMappingImpl()
Construct TypeMapping


           
      
        qName2Pair  = new HashMap();
        class2Pair  = new HashMap();
        pair2SF     = new HashMap();
        pair2DF     = new HashMap();
        namespaces  = new ArrayList();
    
Methods Summary
public DeserializerFactoryfinalGetDeserializer(java.lang.Class javaType, javax.xml.namespace.QName xmlType, TypeMappingDelegate start)

        DeserializerFactory df = null;
        if (javaType != null && javaType.isArray()) {
            Class componentType = javaType.getComponentType();

            // HACK ALERT - Don't return the ArrayDeserializer IF
            // the xmlType matches the component type of the array
	    // or if the componentType is the wrappertype of the
	    // xmlType, because that means we're using maxOccurs 
	    // and/or nillable and we'll want the higher layers to 
	    // get the component type deserializer... (sigh)
            if (xmlType != null) {
                Class actualClass = start.getClassForQName(xmlType);
                if (actualClass == componentType
                    || (actualClass != null && (componentType.isAssignableFrom(actualClass)
                        || Utils.getWrapperType(actualClass.getName()).equals(componentType.getName())))) {
			return null;
                }
            }
            Pair pair = (Pair) qName2Pair.get(Constants.SOAP_ARRAY);
            df = (DeserializerFactory) pair2DF.get(pair);
            if (df instanceof ArrayDeserializerFactory && javaType.isArray()) {
                QName componentXmlType = start.getTypeQName(componentType);
                if (componentXmlType != null) {
                    df = new ArrayDeserializerFactory(componentXmlType);
                }
            }
        }
        return df;
    
public SerializerFactoryfinalGetSerializer(java.lang.Class javaType)

        Pair pair;
        if (isArray(javaType)) {
            pair = (Pair) qName2Pair.get(Constants.SOAP_ARRAY);
        } else {
            pair = (Pair) class2Pair.get(javaType);
        }
        if (pair != null) {
            return (SerializerFactory)pair2SF.get(pair);
        }

        return null;
    
public java.lang.Class[]getAllClasses(TypeMappingDelegate next)
Returns an array of all the classes contained within this mapping

        java.util.HashSet temp = new java.util.HashSet();
        if (next != null)
        {
            temp.addAll(java.util.Arrays.asList(next.getAllClasses()));
        }
        temp.addAll(class2Pair.keySet());
        return (Class[])temp.toArray(new Class[temp.size()]);
    
public java.lang.ClassgetClassForQName(javax.xml.namespace.QName xmlType, java.lang.Class javaType, TypeMappingDelegate next)

        if (xmlType == null) {
            return null;
        }

        //log.debug("getClassForQName xmlType =" + xmlType);

        if (javaType != null) {
            // Looking for an exact match first
            Pair pair = new Pair(javaType, xmlType);
            if (pair2DF.get(pair) == null) {
                if (next != null) {
                    javaType = next.getClassForQName(xmlType, javaType);
                }
            }
        }

        if (javaType == null) {
            //look for it in our map
            Pair pair = (Pair) qName2Pair.get(xmlType);
            if (pair == null && next != null) {
                //on no match, delegate
                javaType = next.getClassForQName(xmlType);
            } else if (pair != null) {
                javaType = pair.javaType;
            }
        }
        
        //log.debug("getClassForQName javaType =" + javaType);
        if(javaType == null && shouldDoAutoTypes()) {
            String pkg = Namespaces.getPackage(xmlType.getNamespaceURI());
            if (pkg != null) {
                String className = xmlType.getLocalPart();
                if (pkg.length() > 0) {
                    className = pkg + "." + className;
                }
                try {
                    javaType = ClassUtils.forName(className);
                    internalRegister(javaType,
                                     xmlType,
                                     new BeanSerializerFactory(javaType, xmlType),
                                     new BeanDeserializerFactory(javaType, xmlType));
                } catch (ClassNotFoundException e) {
                }
            }
        }
        return javaType;
    
public javax.xml.rpc.encoding.DeserializerFactorygetDeserializer(java.lang.Class javaType, javax.xml.namespace.QName xmlType, TypeMappingDelegate start)
Gets the DeserializerFactory registered for the specified pair of Java type and XML data type.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
return
Registered DeserializerFactory
throws
JAXRPCException - If there is no registered DeserializerFactory for this pair of Java type and XML data type java.lang.IllegalArgumentException - If invalid or unsupported XML/Java type is specified

        if (javaType == null) {
            javaType = start.getClassForQName(xmlType);
            // If we don't have a mapping, we're hosed since getClassForQName()
            // has already asked all our delegates.
            if (javaType == null) {
                return null;
            }
        }

        Pair pair = new Pair(javaType, xmlType);

        return (javax.xml.rpc.encoding.DeserializerFactory) pair2DF.get(pair);
    
public javax.xml.rpc.encoding.SerializerFactorygetSerializer(java.lang.Class javaType, javax.xml.namespace.QName xmlType)
Gets the SerializerFactory registered for the specified pair of Java type and XML data type.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
return
Registered SerializerFactory
throws
JAXRPCException - If there is no registered SerializerFactory for this pair of Java type and XML data type java.lang.IllegalArgumentException - If invalid or unsupported XML/Java type is specified


        javax.xml.rpc.encoding.SerializerFactory sf = null;

        // If the xmlType was not provided, get one
        if (xmlType == null) {
            xmlType = getTypeQName(javaType, null);
            // If we couldn't find one, we're hosed, since getTypeQName()
            // already asked all of our delegates.
            if (xmlType == null) {
                return null;
            }
        }

        // Try to get the serializer associated with this pair
        Pair pair = new Pair(javaType, xmlType);

        // Now get the serializer with the pair
        sf = (javax.xml.rpc.encoding.SerializerFactory) pair2SF.get(pair);

        // Need to look into hierarchy of component type.
        // ex) java.util.GregorianCalendar[]
        //     -> java.util.Calendar[]
        if (sf == null && javaType.isArray()) {
            int dimension = 1;
            Class componentType = javaType.getComponentType();
            while (componentType.isArray()) {
                dimension += 1;
                componentType = componentType.getComponentType();
            }
            int[] dimensions = new int[dimension];
            componentType = componentType.getSuperclass();
            Class superJavaType = null;
            while (componentType != null) {
    			superJavaType = Array.newInstance(componentType, dimensions).getClass();
                pair = new Pair(superJavaType, xmlType);
                sf = (javax.xml.rpc.encoding.SerializerFactory) pair2SF.get(pair);
                if (sf != null) {
                    break;
                }
                componentType = componentType.getSuperclass();
            }
        }
        
        // check if ArrayOfT(xml)->T[](java) conversion is possible
        if (sf == null && javaType.isArray() && xmlType != null) {
            Pair pair2 = (Pair) qName2Pair.get(xmlType);
            if (pair2 != null 
                    && pair2.javaType != null
                    && !pair2.javaType.isPrimitive() 
                    && ArrayUtil.isConvertable(pair2.javaType, javaType)) {
                sf = (javax.xml.rpc.encoding.SerializerFactory) pair2SF.get(pair2);
            }
        }
        
        // find serializer with xmlType
        if (sf == null && !javaType.isArray() 
                && !Constants.isSchemaXSD(xmlType.getNamespaceURI()) 
                && !Constants.isSOAP_ENC(xmlType.getNamespaceURI())) {
            Pair pair2 = (Pair) qName2Pair.get(xmlType);
            if (pair2 != null && pair2.javaType != null 
                    && !pair2.javaType.isArray()                         // for array
                    && (javaType.isAssignableFrom(pair2.javaType) || 
                       (pair2.javaType.isPrimitive() && javaType == JavaUtils.getWrapperClass(pair2.javaType))))       // for derived type (xsd:restriction) 
            {
                sf = (javax.xml.rpc.encoding.SerializerFactory) pair2SF.get(pair2);
            }
        }
        
        return sf;
    
public java.lang.String[]getSupportedEncodings()
Gets the list of encoding styles supported by this TypeMapping object.

return
String[] of namespace URIs for the supported encoding styles and XML schema namespaces.

        String[] stringArray = new String[namespaces.size()];
        return (String[]) namespaces.toArray(stringArray);
    
public javax.xml.namespace.QNamegetTypeQName(java.lang.Class javaType, TypeMappingDelegate next)

        QName xmlType = getTypeQNameExact(javaType, next);

        /* If auto-typing is on and the array has the default SOAP_ARRAY QName,
         * then generate a namespace for this array intelligently.   Also
         * register it's javaType and xmlType. List classes and derivitives
         * can't be used because they should be serialized as an anyType array.
         */
        if ( shouldDoAutoTypes() &&
             javaType != List.class &&
             !List.class.isAssignableFrom(javaType) &&
             xmlType != null &&
             xmlType.equals(Constants.SOAP_ARRAY) )
        {
            xmlType = new QName(
                Namespaces.makeNamespace( javaType.getName() ),
                Types.getLocalNameFromFullName( javaType.getName() ) );

            internalRegister( javaType,
                              xmlType,
                              new ArraySerializerFactory(),
                              new ArrayDeserializerFactory() );
        }

        // Can only detect arrays via code
        if (xmlType == null && isArray(javaType)) {

            // get the registered array if any
            Pair pair = (Pair) class2Pair.get(Object[].class);
            // TODO: it always returns the last registered one,
            //  so that's why the soap 1.2 typemappings have to 
            //  move to an other registry to differentiate them
            if (pair != null) {
                xmlType = pair.xmlType;
            } else {
                xmlType = Constants.SOAP_ARRAY;
            }
        }

        /* If the class isn't an array or List and auto-typing is turned on,
        * register the class and it's type as beans.
        */
        if (xmlType == null && shouldDoAutoTypes())
        {
            xmlType = new QName(
                Namespaces.makeNamespace( javaType.getName() ),
                Types.getLocalNameFromFullName( javaType.getName() ) );

            /* If doAutoTypes is set, register a new type mapping for the
            * java class with the above QName.  This way, when getSerializer()
            * and getDeserializer() are called, this QName is returned and
            * these methods do not need to worry about creating a serializer.
            */
            internalRegister( javaType,
                              xmlType,
                              new BeanSerializerFactory(javaType, xmlType),
                              new BeanDeserializerFactory(javaType, xmlType) );
        }

        //log.debug("getTypeQName xmlType =" + xmlType);
        return xmlType;
    
public javax.xml.namespace.QNamegetTypeQNameExact(java.lang.Class javaType, TypeMappingDelegate next)
Get the QName for this Java class, but only return a specific mapping if there is one. In other words, don't do special array processing, etc.

param
javaType
return

        if (javaType == null)
            return null;
       
        QName xmlType = null;
        Pair pair = (Pair) class2Pair.get(javaType);

        if (isDotNetSoapEncFixNeeded() && pair != null ) {
            // Hack alert!
            // If we are in .NET bug compensation mode, skip over any
            // SOAP Encoded types we my find and prefer XML Schema types
            xmlType = pair.xmlType;
            if (Constants.isSOAP_ENC(xmlType.getNamespaceURI()) &&
                    !xmlType.getLocalPart().equals("Array")) {
                pair = null;
            }
        }

        if (pair == null && next != null) {
            // Keep checking up the stack...
            xmlType = next.delegate.getTypeQNameExact(javaType,
                                                      next.next);
        }

        if (pair != null) {
            xmlType = pair.xmlType;
        }

        return xmlType;
    
public javax.xml.namespace.QNamegetTypeQNameRecursive(java.lang.Class javaType)
Gets the QName for the type mapped to Class.

param
javaType class or type
return
xmlType qname or null

        QName ret = null;
        while (javaType != null) {
            ret = getTypeQName(javaType, null);
            if (ret != null)
                return ret;

            // Walk my interfaces...
            Class [] interfaces = javaType.getInterfaces();
            if (interfaces != null) {
                for (int i = 0; i < interfaces.length; i++) {
                    Class iface = interfaces[i];
                    ret = getTypeQName(iface, null);
                    if (ret != null)
                        return ret;
                }
            }

            javaType = javaType.getSuperclass();
        }
        return null;
    
public javax.xml.namespace.QNamegetXMLType(java.lang.Class javaType, javax.xml.namespace.QName xmlType, boolean encoded)
Get the exact XML type QName which will be used when serializing a given Class to a given type QName. In other words, if we have: Class TypeQName ---------------------- Base myNS:Base Child myNS:Child and call getXMLType(Child.class, BASE_QNAME), we should get CHILD_QNAME.

param
javaType
param
xmlType
return
the type's QName
throws
JAXRPCException

        javax.xml.rpc.encoding.SerializerFactory sf = null;

        // If the xmlType was not provided, get one
        if (xmlType == null) {
            xmlType = getTypeQNameRecursive(javaType);

            // If we couldn't find one, we're hosed, since getTypeQName()
            // already asked all of our delegates.
            if (xmlType == null) {
                return null;
            }
        }

        // Try to get the serializer associated with this pair
        Pair pair = new Pair(javaType, xmlType);

        // Now get the serializer with the pair
        sf = (javax.xml.rpc.encoding.SerializerFactory) pair2SF.get(pair);
        if (sf != null)
            return xmlType;

        // If not successful, use the xmlType to get
        // another pair.  For some xmlTypes (like SOAP_ARRAY)
        // all of the possible javaTypes are not registered.
        if (isArray(javaType)) {
            if (encoded) {
                return Constants.SOAP_ARRAY;
            } else {
                pair = (Pair) qName2Pair.get(xmlType);
            }
        }

        if (pair == null) {
            pair = (Pair) class2Pair.get(javaType);
        }

        if (pair != null) {
            xmlType = pair.xmlType;
        }
        return xmlType;
    
protected voidinternalRegister(java.lang.Class javaType, javax.xml.namespace.QName xmlType, javax.xml.rpc.encoding.SerializerFactory sf, javax.xml.rpc.encoding.DeserializerFactory dsf)
Internal version of register(), which allows null factories.

param
javaType
param
xmlType
param
sf
param
dsf
throws
JAXRPCException

        // Both javaType and xmlType must be specified.
        if (javaType == null || xmlType == null) {
            throw new JAXRPCException(
                    Messages.getMessage(javaType == null ?
                                         "badJavaType" : "badXmlType"));
        }

        //REMOVED_FOR_TCK
        //if (sf != null &&
        //    !(sf instanceof javax.xml.rpc.encoding.SerializerFactory)) {
        //    throw new JAXRPCException(message text);
        //}
        //if (dsf != null &&
        //    !(dsf instanceof javax.xml.rpc.encoding.DeserializerFactory)) {
        //    throw new JAXRPCException(message text);
        //}

        Pair pair = new Pair(javaType, xmlType);

        // This code used to not put the xmlType and the JavaType
        // in the maps if it already existed:
        //    if ((dsf != null) || (qName2Pair.get(xmlType) == null))
        // This goes against the philosphy that "last one registered wins".
        // In particular, the mapping for java.lang.Object --> anyType
        // was coming out in WSDL generation under the 1999 XML Schema
        // namespace, which .NET doesn't understand (and is not great anyway).
        qName2Pair.put(xmlType, pair);
        class2Pair.put(javaType, pair);

        if (sf != null)
            pair2SF.put(pair, sf);
        if (dsf != null)
            pair2DF.put(pair, dsf);
    
private static booleanisArray(java.lang.Class clazz)

        return clazz.isArray() || java.util.Collection.class.isAssignableFrom(clazz);
    
private booleanisDotNetSoapEncFixNeeded()
isDotNetSoapEncFixNeeded - Do we need to compensate for the dotnet bug. check the service specific flag before using the global flag

return

        MessageContext msgContext = MessageContext.getCurrentContext();
        if (msgContext != null) {
            SOAPService service = msgContext.getService();
            if (service != null) {
                String dotNetSoapEncFix = (String) service.getOption(AxisEngine.PROP_DOTNET_SOAPENC_FIX);
                if (dotNetSoapEncFix != null) {
                    return JavaUtils.isTrue(dotNetSoapEncFix);
                }
            }
        }
        return TypeMappingImpl.dotnet_soapenc_bugfix;
    
public booleanisRegistered(java.lang.Class javaType, javax.xml.namespace.QName xmlType)
isRegistered returns true if the [javaType, xmlType] pair is registered.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
return
true if there is a mapping for the given pair, or false if the pair is not specifically registered. For example if called with (java.lang.String[], soapenc:Array) this routine will return false because this pair is probably not specifically registered. However if getSerializer is called with the same pair, the default TypeMapping will use extra logic to find a serializer (i.e. array serializer)

        if (javaType == null || xmlType == null) {
            // REMOVED_FOR_TCK
            // return false;
            throw new JAXRPCException(
                    Messages.getMessage(javaType == null ?
                                         "badJavaType" : "badXmlType"));
        }
        if (pair2SF.keySet().contains(new Pair(javaType, xmlType))) {
            return true;
        }
        return false;
    
public voidregister(java.lang.Class javaType, javax.xml.namespace.QName xmlType, javax.xml.rpc.encoding.SerializerFactory sf, javax.xml.rpc.encoding.DeserializerFactory dsf)
Registers SerializerFactory and DeserializerFactory for a specific type mapping between an XML type and Java type.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
param
sf - SerializerFactory
param
dsf - DeserializerFactory
throws
JAXRPCException - If any error during the registration

        // At least a serializer or deserializer factory must be specified.
        if (sf == null && dsf == null) {
            throw new JAXRPCException(Messages.getMessage("badSerFac"));
        }

        internalRegister(javaType, xmlType, sf, dsf);
    
public voidremoveDeserializer(java.lang.Class javaType, javax.xml.namespace.QName xmlType)
Removes the DeserializerFactory registered for the specified pair of Java type and XML data type.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
throws
JAXRPCException - If there is error in removing the registered DeserializerFactory

        if (javaType == null || xmlType == null) {
            throw new JAXRPCException(
                    Messages.getMessage(javaType == null ?
                                         "badJavaType" : "badXmlType"));
        }
        Pair pair = new Pair(javaType, xmlType);
        pair2DF.remove(pair);
    
public voidremoveSerializer(java.lang.Class javaType, javax.xml.namespace.QName xmlType)
Removes the SerializerFactory registered for the specified pair of Java type and XML data type.

param
javaType - Class of the Java type
param
xmlType - Qualified name of the XML data type
throws
JAXRPCException - If there is error in removing the registered SerializerFactory

        if (javaType == null || xmlType == null) {
            throw new JAXRPCException(
                    Messages.getMessage(javaType == null ?
                                         "badJavaType" : "badXmlType"));
        }

        Pair pair = new Pair(javaType, xmlType);
        pair2SF.remove(pair);
    
public voidsetDoAutoTypes(boolean doAutoTypes)

        this.doAutoTypes = doAutoTypes ? Boolean.TRUE : Boolean.FALSE;
    
public voidsetSupportedEncodings(java.lang.String[] namespaceURIs)
Sets the list of encoding styles supported by this TypeMapping object. (Not sure why this is useful...this information is automatically updated during registration.

param
namespaceURIs String[] of namespace URI's

        namespaces.clear();
        for (int i =0; i< namespaceURIs.length; i++) {
            if (!namespaces.contains(namespaceURIs[i])) {
                namespaces.add(namespaceURIs[i]);
            }
        }
    
public booleanshouldDoAutoTypes()

        if(doAutoTypes != null) {
            return doAutoTypes.booleanValue();
        }
        MessageContext msgContext = MessageContext.getCurrentContext();
        if(msgContext != null) {
            if (msgContext.isPropertyTrue("axis.doAutoTypes") ||
                    (msgContext.getAxisEngine() != null && JavaUtils.isTrue(msgContext.getAxisEngine().getOption("axis.doAutoTypes")))) {
                doAutoTypes = Boolean.TRUE;
            }
        }
        if(doAutoTypes == null){
            doAutoTypes = AxisProperties.getProperty("axis.doAutoTypes",
                    "false")
                    .equals("true") ?
                    Boolean.TRUE : Boolean.FALSE;
        }
        return doAutoTypes.booleanValue();