wiki:ExampleUsingOwnConceteTypes

Version 4 (modified by lauer, 17 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()} ) );
...