Version 5 (modified by lauer, 18 years ago) (diff) |
---|
Using own concete types
Special case: Using own types in Collections and Maps. Java's type erasure in action!
Server side
We want to use the type Param in our API. Normally, this will cause an error message. See how we can make this type XML-RPC compliant with only a few lines of code:
public interface Api { Param returnParam(); void passAsParameter( Param p ); } public class Impl implements Api { public Param returnParam() { return createParam( ... ); } void passAsParameter( Param p ) { doSomethingWith( p ); } }
To use type Param, we have to make it XML-RPC compliant. We use java annotations and user-defined conversion operations to do this.
- the @XmlRpc annotation declares that type Param uses XML-RPC type ARRAY as transport representation
- The interface {{{Convertable}} declares what specific java type is used for transfer via XML-RPC
- toXmlRpc converts an instance of type Param into its XML-RPC representation
- the constructor creates an instance of type Param back from it's XML-RPC representation
@XmlRpc( type=Type.ARRAY ) public class Param implements Convertable<Collection<String>> { public Param( Collection<String> xmlRpcRepresentation ) { ... } public Collection<String> toXmlRpc() { return ... } }
Now our type ist XML-RPC compliant! We can register the implementation as usual...
WebServer xmlRpcServer = new WebServer( port ); xmlRpcServer.addHandler( "handlerId", XmlRpcHandlerFactory.createHandlerFor( new Impl() ); xmlRpcServer.start();
Client Side
Our client can be used without any extra statements:
Api remote_api = XmlRpc.createClient( Api.class, "handlerId", host, port ); Param p = remote_api.returnParam(); Param asParam = ...; remote_api.passAsParameter( asParam ); ...
Using own types in Collections and Maps
When turning generics into thier class representation, java runs a so called type erasure, reducing a Collection<Param> to a simple Collection. Thus, the XML-RPC runtime system cannot determine the content type of this collection unless the user places an extra hint using the @Contains annotation.
// DOES NOT WORK: Map<String,Param> will be reduced to Map, Collection<Param> will be reduced to Collection public interface Api { Map<String,Param> returnMyParamInMap(); void passManyParams( Collection<Param> params ); }
Place a @Contains in front of the method to annotate a return type. Place it before a formal parameter to annotate method parameters.
// WORKS! public interface Api { @Contains(Param.class) Map<String,Param> returnMyParamInMap(); void passManyParams( @Contains(Param.class) Collection<Param> params ); }
Client Side
Now remote clients can also use Collections and Maps containing own types:
Api remote_api = XmlRpc.createClient( Api.class, "handlerId", host, port ); Map<String,Param> map = remote_api.returnMyParamInMap(); for( Param p : map.values() ) { ... } remote_api.passManyParams( Collections.asList( new Param[]{new Param(), new Param()} ) ); ...
Examples in source code: http://delight.opendfki.de/repos/trunk/XmlRpcDelight/src/examples/de/dfki/util/xmlrpc/examples/concrete_types/