Glen addressed a similar issue on axis-user today.

The deserialization engine always deserializes arrays into ArrayList
objects.

Rich Scheuerle
XML & Web Services Development
512-838-5115  (IBM TL 678-5115)


                                                                                       
                                           
                      "David L. Cole"                                                  
                                           
                      <DLCole@cmsenergy        To:       [EMAIL PROTECTED]       
                                           
                      .com>                    cc:       [EMAIL PROTECTED]      
                                           
                                               Subject:  Deserialization issue         
                                           
                      02/08/2002 11:27                                                 
                                           
                      AM                                                               
                                           
                      Please respond to                                                
                                           
                      axis-dev                                                         
                                           
                                                                                       
                                           
                                                                                       
                                           



Hi all,

Has anybody noticed an anonymoly occurring as follows:


I have the following 2 test classes (simplified here for brevity)

public class DataWrapper
{
    private HashMap storage; //Primary object storage
    private long startTime;  //Used to store an arbitrary start time
    private long endTime;    //Used to store an arbitrary end time
}

public class User
{
    private long userID;
    private String userName;
    private String password;
}



I also have a stateless session bean which contains the following method:

     public DataWrapper timedGetAllUsers()
     {
        long startTime = System.currentTimeMillis();

        User[] users = getAllUsers();

        DataWrapper wrapper = new DataWrapper(new HashMap(users.length));
        wrapper.setStartTime(startTime);

        if(users != null)
        {
            HashMap map = new HashMap();
            map.put("users",users);
            wrapper.setStorage(map);
        }

        wrapper.setEndTime(System.currentTimeMillis());
        return wrapper;
     }

NOTE: Notice that in the above method we add a User[] with the key "users"
to a HashMap and then set the storage attribute to the new HashMap
     inside the DataWrapper class.


On my client app (a Swing client) I execute the method using Axis in the
following manner:

    private DataWrapper getAllUsersUsingAxisSoap()
    {
        DataWrapper retVal = null;
        org.apache.axis.client.Service service = null ;
        org.apache.axis.client.Call call = null ;

        try {
            service = new org.apache.axis.client.Service();
            call = (org.apache.axis.client.Call) service.createCall();
        }
        catch(Exception t) {
            t.printStackTrace();
        }

        try
        {
            Class cls = com.itemxchange.users.data.User.class;
            Class wrapperClass =
com.itemxchange.util.data.DataWrapper.class;

            java.net.URL endpointURL = new java.net.URL
("http://localhost:7001/axis/servlet/AxisServlet";);
            call.setTargetEndpointAddress( endpointURL );

call.setProperty(org.apache.axis.transport.http.HTTPTransport.URL,
endpointURL.toString());

            if
(call.getProperty(org.apache.axis.transport.http.HTTPTransport.URL) ==
null)
            {
                throw new org.apache.axis.NoEndPointException();
            }

            call.removeAllParameters();
            call.setReturnType(new org.apache.axis.encoding.XMLType(new

            javax.xml.rpc.namespace.QName
("http://schemas.xmlsoap.org/soap/encoding/";, "DataWrapper")));

            // set the namespace and serializer/deserializer for the user
object and DataWrapper classes
            org.apache.axis.encoding.BeanSerializer beanSerial = new
org.apache.axis.encoding.BeanSerializer(cls);
            org.apache.axis.encoding.BeanSerializer wrapperBeanSerial = new
org.apache.axis.encoding.BeanSerializer(wrapperClass);

            javax.xml.rpc.namespace.QName qn = new
javax.xml.rpc.namespace.QName("urn:UserManagerEJB", "user");
            javax.xml.rpc.namespace.QName wrapperQN = new
javax.xml.rpc.namespace.QName("urn:UserManagerEJB", "DataWrapper");

            call.addDeserializerFactory(wrapperQN, wrapperClass,
wrapperBeanSerial.getFactory());
            call.addDeserializerFactory(qn, cls, beanSerial.getFactory());


call.setProperty(org.apache.axis.transport.http.HTTPTransport.ACTION, "");
            call.setProperty(call.NAMESPACE, "UserManager");

            call.setOperationName( "timedGetAllUsers");

            Object resp = null;
            try
            {
                resp = call.invoke(new Object[] {});
            }
            catch(Exception e)
            {
                log("Caught exception during call.invoke()");
                e.printStackTrace();
            }

           if (resp instanceof java.rmi.RemoteException)
           {
                ((java.rmi.RemoteException)resp).printStackTrace();
                throw (java.rmi.RemoteException)resp;
            }
            else {
                 try
                 {
                    retVal
= (DataWrapper)org.apache.axis.utils.JavaUtils.convert(resp,DataWrapper.class);

                 }
                 catch(Exception e)
                 {
                    log("Caught exception during convert.");
                    e.printStackTrace();
                 }
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return retVal;
    }

And here is the DD:

<deployment xmlns="http://xml.apache.org/axis/wsdd/";
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java";>

     <service name="UserManager" provider="java:RPC">
          <parameter name="className"
                  value="com.itemxchange.users.ejb.UserManagerEJB"/>
          <parameter name="methodName"
                  value="*"/>
          <beanMapping qname="ns:user"
                    xmlns:ns="urn:UserManagerEJB"
                    languageSpecificType
="java:com.itemxchange.users.data.User"/>
          <beanMapping qname="ns:DataWrapper"
                    xmlns:ns="urn:UserManagerEJB"
                    languageSpecificType
="java:com.itemxchange.util.data.DataWrapper"/>
     </service>
</deployment>


The problem which occurs is after the call returns successfully, the
DataWrapper object's storage HashMap should have an array of Users (User[])
stored inside for the key "users". Instead of a User[], the value for
"users" has come back as an ArrayList.

Here is the method used to extract the User[] from the DataWrapper object:

    private User[] getUserArrayFromWrapper(DataWrapper wrapper)
    {
        User[] usersArray = null;
        HashMap map = wrapper.getStorage();

        //Pull out the Users[] as an Object by the key 'users'
        Object usersArrayObject = null;
        if(map != null)
        {
            usersArrayObject = map.get("users");
            if(usersArrayObject != null)
            {
                log("getUserArrayFromWrapper: usersArrayObject class: "+
usersArrayObject.getClass().getName());
            }
            else
            {
                log("getUserArrayFromWrapper: usersArrayObject is NULL!");
                log("getUserArrayFromWrapper: contents of Storage Map: " +
map);
            }
        }
        else
        {
            log("getUserArrayFromWrapper: Storage Map is NULL!");
        }

        //If the protocol was Apache-Axis, the usersArrayObject will be
returned
        //internally as an ArrayList, else it will be simply a User[] as
expected
        //If the protocol is Apache-Soap2.0 or Weblogic SOAP or RMI, the
usersArrayObject
        //will be the User[] as expected.
        if(usersArrayObject instanceof ArrayList)
        {
            usersArray = (User[])((ArrayList)usersArrayObject).toArray(new
User[0]);
        }
        else
        {
            usersArray = (User[])usersArrayObject;
        }

        return usersArray;
    }

I am guessing that this is simply an oversight. Upon getting the object out
of the HashMap, I am having to cast it to an ArrayList and subsequently
call the toArray() method on the ArrayList to get the expected User[].

Any comments and/or suggestions?

Thanks,
David Cole





Reply via email to