I would like to use a dynamic proxy using Proxy.newProxyInstance
for a generated classes (Swagger) and these are not implementing an interface, which brought me to ByteBuddy, using which it should allow me to build the interface required by Proxy.newProxyInstance
.
I got so far:
Class<?> restClass = RestServiceApi.class;
Builder<?> builder = byteBuddy.makeInterface().merge(Visibility.PUBLIC).name(restClass.getName() + "I");
for (Method method : restClass.getMethods()) {
builder = builder.defineMethod(method.getName(),
HOW_TO_DO_THIS);
}
Class<?> restInterface = builder.make().load(this.getClass().getClassLoader()).getLoaded();
Class<?>[] proxyInterfaces = new Class<?>[] { restInterface };
// TODO create manipulatedRestServiceApiThatImplementsRestInterfaceI
asyncServiceProxy = new AsynchronousServiceProxy<>(RestServiceApi.class, errorHandler, guiBlockingListener);
ctrAsyncService = (manipulatedRestServiceApiThatImplementsRestInterfaceI) Proxy.newProxyInstance(RestServiceApi.class.getClassLoader(), proxyInterfaces, asyncServiceProxy);
Even if can figure out, how to write the code required to to define each method, I get the feeling, that I'm not doing it in the correct way, that I'm going to write a massive amount of code to translate the reflection information of Method
to whatever ByteBudd requires and I suspect there is an easier way to build this interface class.
I would very much appreciate if anyone can point me into the correct direction.
Turned out that my hunch was correct (I was going at it from the wrong angle) and should have asked the question more broadly. What I actually needed (but didn't ask) was a solution to building dynamic proxies where you don't have a service interface but a service class.
With a service interface, you can use java.lang.reflect.Proxy
to build a dynamic service proxy:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), new Class[] { ServiceInterface.class }, serviceProxy);
proxiedService.methodOfServiceInterface();
The statement proxiedService.methodOfServiceInterface()
and will call the method MyInvocationHandler.invoke(Object proxy, final Method method, final Object[] arguments)
which can do whatever is needed to execute the actual method (e.g. via remote method invocation).
This approach works fine to call EJBs or SOAP services where you have an interface, but breaks with a service class. So what I actually needed was an algorithm to build a dynamic service proxy that works for both service interfaces and service classes.
Building the dynamic service proxy with ByteBuddy was actually quite simple. The following generic method implements the required algorithm:
/**
* Creates a service proxy to call methods of the service class/interface.
*
* @param <T> type of service class or interface
* @param serviceClassOrInterface service class or interface
* @param serviceProxy the service proxy
* @return service proxy
*/
public static <T> T createDynamicProxy(Class<T> serviceClassOrInterface, MyInvocationHandler<T> serviceProxy) {
try {
return new ByteBuddy()
.subclass(serviceClassOrInterface)
.method(isDeclaredBy(serviceClassOrInterface))
.intercept(InvocationHandlerAdapter.of(serviceProxy))
.make()
.load(serviceClassOrInterface.getClassLoader())
.getLoaded().getConstructor().newInstance();
} catch (Exception exception) {
throw new RuntimeException("Error creating dynamic proxy of " + serviceClassOrInterface.getName(), exception);
}
}
which can be used like this:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = createDynamicProxy(serviceInterface, serviceProxy);