I have a service where Guice handles the dependency injection for the service. I have a use case where for one the beans being injected via Guice I have to mock/proxy one of the method calls for that bean. I am trying to do this via Byte-Buddy and its method interception. Initially I tried to proxy the method calls via CGLib and was able to make it work. But when I tried to move to Byte-Buddy since CGLib is deprecated and they recommend Byte-Buddy, the guice injector is rejecting the proxied bean for it.
This is the error I am getting -
Caused by: com.google.inject.CreationException: Unable to create injector, see the following errors:
1) [Guice/ErrorInCustomProvider]: IllegalStateException: Illegal interface class DependencyClientImpl for class DependencyClientImpl$ByteBuddy$EAI3cbku
at ClientModule.getDependencyClient(ClientModule.java:146)
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Unknown Source)
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(Unknown Source)
at com.google.inject.internal.InternalInjectorCreator.build(Unknown Source)
at com.google.inject.Guice.createInjector(Unknown Source)
at com.google.inject.Guice.createInjector(Unknown Source)
at com.google.inject.Guice.createInjector(Unknown Source)
at com.vegeta.myservice.MyService.main(MyService.java:55)
... 5 more
Caused by: java.lang.IllegalStateException: Illegal interface class com.vegeta.dependencyservice.DependencyClientImplfor class com.vegeta.dependencyservice.DependencyClientImpl$ByteBuddy$EAI3cbku
at net.bytebuddy.dynamic.scaffold.InstrumentedType$Default.validated(InstrumentedType.java:1572)
at net.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:519)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:212)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:203)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4050)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3734)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3986)
at com.vegeta.myservice.bytebuddy.ProxyBuilder.createProxy(ProxyBuilder.java:19)
at com.vegeta.myservice.module.ClientModule.getDependencyClient(ClientModule.java:160)
at com.vegeta.myservice.module.ClientModule$$FastClassByGuice$$5d163b.GUICE$TRAMPOLINE(<generated>)
at com.vegeta.myservice.module.ClientModule$$FastClassByGuice$$5d163b.apply(<generated>)
at com.google.inject.internal.ProviderMethod$FastClassProviderMethod.doProvision(Unknown Source)
at com.google.inject.internal.ProviderMethod.doProvision(Unknown Source)
at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(Unknown Source)
at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(Unknown Source)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(Unknown Source)
at com.google.inject.internal.SingletonScope$1.get(Unknown Source)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(Unknown Source)
at com.google.inject.internal.SingleParameterInjector.inject(Unknown Source)
at com.google.inject.internal.SingleParameterInjector.getAll(Unknown Source)
at com.google.inject.internal.ConstructorInjector.provision(Unknown Source)
at com.google.inject.internal.ConstructorInjector.construct(Unknown Source)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(Unknown Source)
at com.google.inject.internal.FactoryProxy.get(Unknown Source)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(Unknown Source)
at com.google.inject.internal.SingletonScope$1.get(Unknown Source)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(Unknown Source)
at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(Unknown Source)
The code I have written is as follows -
public class ClientModule extends AbstractModule {
@Provides
@Singleton
DependencyClient getDependencyClient()
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
DependencyClient rawObject = new ClientBuilder().newClient();
return ProxyBuilder.createProxy(rawObject, new DependencyInterceptorByteBuddy());
}
}
public interface ProxyInterceptorByteBuddy {
Object intercept(Callable<?> clazz, Method method) throws Exception;
}
public class DependencyInterceptorByteBuddy implements ProxyInterceptorByteBuddy {
@Override
@RuntimeType
public Object intercept(@SuperCall Callable<?> clazz, @Origin Method method) throws Exception {
if ("foobar".equals(method.getName())) {
return 33;
} else {
return clazz.call();
}
}
}
public class ProxyBuilder {
public static <T> T createProxy(T target, ProxyInterceptorByteBuddy interceptor) throws
IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
return (T) new ByteBuddy()
.subclass(target.getClass())
.implement(target.getClass())
.method(ElementMatchers.any())
.intercept(MethodDelegation.to(interceptor))
.make()
// .load(ClassLoader.getSystemClassLoader())
.load(ProxyBuilder.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded()
.getDeclaredConstructor()
.newInstance();
}
}
// When I try to get instance of this bean via injection I get the error -
final DependencyClient client = injector.getInstance(DependencyClient.class);
You are running this code:
.subclass(target.getClass())
.implement(target.getClass())
A direct type will never be an interface, so just delete the second line.