David,
I just committed a chagne to the array deserializer which may fix this
problem.
Please try it out and respond.
Thanks,
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