javaguicebyte-buddy

ByteBuddy Proxy instance Guice Injection Error


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); 

Solution

  • 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.