Domanda

I'm trying to use provider injection to inject a pre-configured object into a factory:

public class CacheBuilderProvider 
    implements Provider<CacheBuilder<Object, Object>> {
    public CacheBuilder<Object, Object> get () {
        //Log the cache builder parameters before creation

        CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
        //configure the cacheBuilder
        return cacheBuilder;
    }
}

public class MyCacheFactory {
    private final CacheBuilder<Object, Object> cacheBuilder;

    @Inject
    public MyFactory(CacheBuilder<Object, Object> cacheBuilder) {
        this.cacheBuilder = cacheBuilder;
    }
}

public class CacheModule extends AbstractModule {            
    @Override
    protected void configure() {
        bind(CacheBuilder.class)
            .toProvider(CacheBuilderProvider.class)
            .in(Singleton.class);
        bind(MyCacheFactory.class)
            .in(Singleton.class);
    }
}

When I use the injector to get a MyCacheFactory instance, I get no log output and an unconfigured CacheBuilder<Object, Object> instance; none of my configuration has been applied. Setting breakpoints verifies that the provider is never being used.

I've also tried applying @Named("MyCacheBuilder") on the appropriate pieces:

public class CacheBuilderProvider 
    implements Provider<CacheBuilder<Object, Object>> {
    @Named("MyCacheBuilder")
    public CacheBuilder<Object, Object> get () { //... }
}

public class MyCacheFactory {
    //...

    @Inject
    public MyFactory(
        @Named("MyCacheBuilder") 
        CacheBuilder<Object, Object> cacheBuilder
    ) {
        //... 
    }
}

When I attempt to run this code, I get a CreationException:

1) No implementation for com.google.common.cache.CacheBuilder
annotated with @com.google.inject.name.Named(value=MyCacheBuilder) was bound.

I've also tried various combinations of raw and generic type references in the class and constructor declarations, with no additional success.

I can work around this by simply creating the provider and binding the instance returned from get() myself, but I expect (and deisre) that Guice will do that for me.

Is there something subtly (or obviously) wrong with my setup?

È stato utile?

Soluzione

This might work:

bind(new TypeLiteral<CacheBuilder<Object, Object>>() {})
          .annotatedWith(Names.named("MyCacheBuilder"))
          .toProvider(CacheBuilderProvider.class)
          .in(Singleton.class);

The bit of magic here is the TypeLiteral class, whose Javadoc documentation you should read. Basically it's a way of allowing you to bind to a generic type (CacheBuilder<Object, Object> in your case). This magic is necessary because Java implements generics using erasure, so you can't just write CacheBuilder<Object, Object>.class.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top