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.