kSOAP2 is a SOAP web service client library for constrained Java environments such as J2ME apps. Ksoap2-android is a fork of kSOAP2 for the Android platform. A typical ksoap2-android client code looks like this.
Inspired by the Spring JDBC template classes, there is below a template for simplifying your kSOAP2 clients:
KSoap2Template.java:
import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; public class KSoap2Template { private static final ResponseMapper<Object> NULL_RESPONSE_MAPPER = new ResponseMapper<Object>() { public Object mapResponse(Object response) { return response; } }; private static final RequestPropertiesSetter NULL_REQUEST_PROPERTIES_SETTER = new RequestPropertiesSetter() { public void setValues(SoapObject request) { // do nothing } }; private String namespace; private String url; private String getUrl() { return url; } private String getNamespace() { return namespace; } public KSoap2Template(String url, String namespace) { this.url = url; this.namespace = namespace; } public void call(String methodName, String soapAction) throws ServiceAccessException { call(methodName, soapAction, NULL_REQUEST_PROPERTIES_SETTER); } public void call(String methodName, String soapAction, RequestPropertiesSetter requestPropertiesSetter) throws ServiceAccessException { call(methodName, soapAction, requestPropertiesSetter, NULL_RESPONSE_MAPPER); } public <T> T call(String methodName, String soapAction, ResponseMapper<T> responseMapper) throws ServiceAccessException { return call(methodName, soapAction, NULL_REQUEST_PROPERTIES_SETTER, responseMapper); } public <T> T call(String methodName, String soapAction, RequestPropertiesSetter requestPropertiesSetter, ResponseMapper<T> responseMapper) throws ServiceAccessException { try { SoapObject request = new SoapObject(getNamespace(), methodName); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); envelope.setOutputSoapObject(request); HttpTransportSE transport = new HttpTransportSE(getUrl()); requestPropertiesSetter.setValues(request); transport.call(soapAction, envelope); return responseMapper.mapResponse(envelope.getResponse()); } catch (Exception e) { throw new ServiceAccessException(e); } } }
ServiceAccessException.java:
public class ServiceAccessException extends RuntimeException { private static final long serialVersionUID = 1L; public ServiceAccessException(Throwable throwable) { super(throwable); } }
RequestPropertiesSetter.java:
import org.ksoap2.serialization.SoapObject; public interface RequestPropertiesSetter { void setValues(SoapObject request); }
ResponseMapper.java:
public interface ResponseMapper<T> { T mapResponse(Object response); }
AbstractResponseMapper.java:
package jbaris.wordpress.com.client.ksoap; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.ksoap2.serialization.PropertyInfo; import org.ksoap2.serialization.SoapObject; public abstract class AbstractResponseMapper<T> implements ResponseMapper<T> { protected <U> U[] getArray(Collection<Object> collection, ResponseMapper<U> itemMapper, Class<U> resultType) { final U[] result = (U[]) Array.newInstance(resultType, collection.size()); final Iterator<Object> iterator = collection.iterator(); for (int i = 0; i < result.length; i++) { result[i] = itemMapper.mapResponse(iterator.next()); } return result; } protected String[] getArray(Object response) { String[] result = new String[0]; if (response instanceof Collection) { final Collection<Object> collection = (Collection<Object>) response; result = new String[collection.size()]; final Iterator<Object> iterator = collection.iterator(); for (int i = 0; i < result.length; i++) { result[i] = iterator.next().toString(); } } else if (response != null) { result = new String[1]; result[0] = response.toString(); } return result; } protected char[] getCharArray(Object response) { char[] result = new char[0]; if (response instanceof Collection) { final Collection<Object> collection = (Collection<Object>) response; result = new char[collection.size()]; final Iterator<Object> iterator = collection.iterator(); for (int i = 0; i < result.length; i++) { final String string = iterator.next().toString(); result[i] = Character.valueOf((char) Integer.parseInt(string)); } } else if (response != null) { result = new char[1]; result[0] = Character.valueOf((char) Integer.parseInt(response .toString())); } return result; } protected List<String> getList(Object response) { final List<String> result = new ArrayList<String>(); if (response instanceof Collection) { final Collection<Object> collection = (Collection<Object>) response; for (final Object item : collection) { result.add(item.toString()); } } else if (response != null) { result.add(response.toString()); } return result; } protected <U> List<U> getList(Object response, Class<U> resultType) { final List<U> result = new ArrayList<U>(); if (response instanceof Collection) { final Collection<Object> collection = (Collection<Object>) response; for (final Object item : collection) { result.add(valueOf(resultType, item.toString())); } } else if (response != null) { result.add(valueOf(resultType, response.toString())); } return result; } protected <U> List<U> getList(Object response, ResponseMapper<U> itemMapper) { final List<U> result = new ArrayList<U>(); if (response instanceof Collection) { final Collection<Object> responseCollection = (Collection<Object>) response; for (final Object soapPrimitive : responseCollection) { result.add(itemMapper.mapResponse(soapPrimitive)); } } else if (response != null) { result.add(itemMapper.mapResponse(response)); } return result; } protected <U> List<U> getList(SoapObject response, String key, ResponseMapper<U> itemMapper) { final List<U> result = new ArrayList<U>(); final int propCount = response.getPropertyCount(); for (int i = 0; i < propCount; i++) { final PropertyInfo propInfo = new PropertyInfo(); response.getPropertyInfo(i, propInfo); if (propInfo.getName().equals(key)) { result.add(itemMapper.mapResponse(propInfo.getValue())); } } return result; } protected String getProperty(SoapObject soapObject, String key) { return soapObject.getProperty(key).toString(); } protected <U> U getProperty(SoapObject soapObject, String key, Class<U> resultType) { return valueOf(resultType, getProperty(soapObject, key)); } protected <U> U getProperty(SoapObject soapObject, String key, ResponseMapper<U> propertyMapper) { return propertyMapper.mapResponse(soapObject.getProperty(key)); } protected <U> U valueOf(Class<U> resultType, Object object) { U result; if (object == null) { result = null; } else { result = valueOf(resultType, object.toString()); } return result; } private <U> U valueOf(Class<U> resultType, String valueAsString) { try { return (U) resultType.getMethod("valueOf", new Class[] { String.class }).invoke(resultType, new Object[] { valueAsString }); } catch (final Exception e) { throw new IllegalStateException(e); } } }
Here are some examples of using the template. Look how simple it becomes your client code:
public class SampleClient { private static final String URL = "http://localhost:8080/ws/SampleService"; private static final String NAMESPACE = "http://sample.org.ar/"; private KSoap2Template template = new KSoap2Template(URL, NAMESPACE); public void callWithVoidResponse() { RequestPropertiesSetter rps = new RequestPropertiesSetter() { public void setValues(SoapObject request) { request.addProperty("aCar", new Car(200L, "A car name")); } }; template.call("addCar", "http://impl.service.sample.org.ar/addCar", rps); } public void callWithoutParams() { template.call("getCarNames", "http://impl.service.sample.org.ar/getCarNames", new AbstractResponseMapper<List<String>>() { public List<String> mapResponse(Object response) { return getList(response); } }); } public Car callWithParamsAndObjectResult() { RequestPropertiesSetter rps = new RequestPropertiesSetter() { public void setValues(SoapObject request) { request.addProperty("carId", 200L); } }; return template.call("getCar", "http://impl.service.sample.org.ar/getCar", rps, new AbstractResponseMapper<Car>() { public Car mapResponse(Object response) { Car result = new Car(); result.setId(getProperty((SoapObject) response, "id", Long.class)); result.setName(getProperty((SoapObject) response, "name")); return result; } }); } }
Obviously this code may be incomplete and may be improved, so comments are welcome.
Nice template. Have you been able to send an array (or arraylist) of complex objects inside in another complex object?
For example:
class AnObject {
private AnotherObject[] array;
…
}
class AnotherObject {
…
}
Yes. Look at http://github.com/jbaris/ksoap2-poc, in particular, http://github.com/jbaris/ksoap2-poc/blob/master/src/test/java/com/wordpress/jbaris/client/ksoap/KSoap2TemplateTest.java
I will post soon about this.
Hi! I’m trying to do a web service j2me client, so I suppouse that I have to use Ksoap in order to return a complextype from the web service. Do you have a simple template, just to give me an idea how I have to do the j2me client?
Thanks a lot!
Hi! I have done my web service client with ksoap but I get this error:
java.lang.NoClassDefFoundError: org/xmlpull/v1/XmlPullParserException
I have added ksoap.jar, kxml.jar, xmlpull.jar, xpp3.jar…and nothings works, do you have an idea of what is it?
Thanks again
how do i pass arraylist (customclass) object
Look at the service:
https://github.com/jbaris/ksoap2-poc/blob/8d9694eaa5dd12b1d4775a6cfdd47a914bc8ecdf/src/main/java/com/wordpress/jbaris/common/services/CarService.java#L21
and its client:
https://github.com/jbaris/ksoap2-poc/blob/8d9694eaa5dd12b1d4775a6cfdd47a914bc8ecdf/src/test/java/com/wordpress/jbaris/client/ksoap/KSoap2TemplateTest.java#L155
Is this what are you looking for? Please be specific.