views:

22

answers:

1

A data provider (java, hibernate) has an API for accessing instances of JPA-annotated classes. A web-service (jax-ws) is exposing the API to the network clients. A bit of a problem I'm thinking to solve is that a client of the data provider cannot be easily reconfigured to either use the provider directly or over the web-service. The reason is that for any persistent class there is a definition of this class in jax-ws client code and in data provider code, they are identical structurally but are different classes in Java. The obvious solution of putting generated classes to the same namespace as the original classes and setting up a class path in such a way that generated classes are always ignored doesn't seem ot be a clean one.

Has anyone solved this or knows a better way?

+1  A: 

One way I've solved this in a similar problem is to work with interfaces and use reflection to build proxy objects that wrap the real underlying object. Something like:

interface IEntity
{
    void setFoo(String foo);

    String getFoo();
}

class WSEntity
{/* code generated by jax-ws */
}

class DataEntity
{ /* code generated by java, hibernate, .. */
}

class WSEntityInvocationHandler implements InvocationHandler
{
    private final WSEntity entity;

    public WSEntityInvocationHandler(WSEntity entity)
    {
        this.entity = entity;
    }

    public Object invoke(Object proxy, 
                         Method method, Object[] args) throws Throwable
    {
        // this is a simplified version
        Method m = entity.getClass().getMethod(method.getName(), params);
        return m.invoke(entity, args);
    }
}

static void example()
{
    InvocationHandler handler = new WSEntityInvocationHandler(entity);
    IEntity ie = (IEntity) Proxy
                 .newProxyInstance(IEntity.class.getClassLoader(),
                                                  new Class[]{IEntity.class},
                                                  handler);
}

Basically all your app would need to do, is decide which "invocation handler" to use, e.g.

InvocationHandler handler = new WSEntityInvocationHandler(entity);

or

InvocationHandler handler = new DataEntityInvocationHandler(entity);
krico