Assisted Inject Implement using Provider as Target

99 views
Skip to first unread message

Matthew Madson

unread,
Dec 2, 2016, 4:42:18 PM12/2/16
to google-guice
Hi Guice Devs:

I assume this is a feature request but I was wondering if there was a way to do something like the following:

interface Factory {

 
@Named("secure")
 
CloseableHttpClient createSecureClient();

 
@Named("insecure")
 
CloseableHttpClient createSecureClient();
}

class Module extends AbstractModule {
 
@Override
 
protected void configure() {
    install
(new FactoryModuleBuilder()
       
.implement(CloseableHttpClient.class, Names.named("secure"), getProvider(Key.get(CloseableHttpClient.class, Names.named("secure"))))
       
.implement(CloseableHttpClient.class, Names.named("insecure"), getProvider(Key.get(CloseableHttpClient.class, Names.named("insecure"))))
       
.build(Factory.class));
 
}
 
 
@Provides
 
@Named("secure")
 
CloseableHttpClient provideSecureHttpClient() {
   
return HttpClientBuilder.create()....build();
 
}

 
@Provides
 
@Named("insecure")
 
CloseableHttpClient provideInsecureHttpClient() {
   
return HttpClientBuilder.create().setSslcontext(SSLContexts.custom().loadTrustMaterial(...).build()).build();
 
}
}

Basically I'd like to have the factory method bound to a provides method.

Best,
Matt

Tavian Barnes

unread,
Dec 3, 2016, 2:24:34 PM12/3/16
to google-guice
Since there are no assisted parameters here, nothing prevents you from just writing an implementation of Factory by hand.

But if there were assisted parameters, how would you expect it to work?

Matthew Madson

unread,
Dec 4, 2016, 3:16:51 AM12/4/16
to google-guice
Thanks for the suggestion re traditional factory; that's actually exactly what I ended up doing but the amount of boilerplate was a bit disappointing. I'll admit I didn't really give the matter much thought beyond my use case so assisted Inject parameters do pose a bit of a problem from a more general design perspective. My suggesting, we're the feature to be implemented, would be to permit assisted annotated parameters on either the provides method or the constructor of the provider type should one exist. I can see how this introduces a bit of perhaps unnecessary complexity since the results of assisted provides methods can longer be injected without use of the assisted factory, but then again I think it could all work out with a bit of documentation.

Tavian Barnes

unread,
Dec 4, 2016, 4:47:08 PM12/4/16
to google-guice
On Sunday, 4 December 2016 03:16:51 UTC-5, Matthew Madson wrote:
Thanks for the suggestion re traditional factory; that's actually exactly what I ended up doing but the amount of boilerplate was a bit disappointing. I'll admit I didn't really give the matter much thought beyond my use case so assisted Inject parameters do pose a bit of a problem from a more general design perspective. My suggesting, we're the feature to be implemented, would be to permit assisted annotated parameters on either the provides method

@Provides definitely can't handle this.  It may be possible to implement some other annotation like @AssistedProvides though, but I haven't thought about it in detail.
 
or the constructor of the provider type should one exist.

This is already how assisted inject works.  It didn't work for you in this case, because you don't have a simple subclass, but rather a whole expression to run that produces the implementation.  But if you just had InsecureHttpClient and SecureHttpClient implementation classes, with @AssistedInject constructors, everything would work automagically.

Matthew Madson

unread,
Dec 5, 2016, 5:57:20 PM12/5/16
to google-guice
Hi Tavian,

I'm curious why you think that @Provides method can't handle it. Wouldn't the following be sufficient?

install(new FactoryModuleBuilder()
   
// this line would tell guice that instances of Foo must come from FooFactory and the provider is only
   
// to be used by the assisted inject FooFactory proxy
   
.implement(Foo.class, (Provider<Foo>) getProvider(Foo.class))
   
.build(FooFactory.class)

@Provides
Foo provideFoo(@Assisted String someRuntimeString) {
 
return new Foo(someRuntimeString);
}

OR

public class FooProvider implements Provider<Foo> {

 
private final String someRuntimeString;
 
 
@Inject
 
public FooProvider(final String someRuntimeString) {
   
this.someRuntimeString = someRuntimeString;
 
}
 
 
@Override
 
public Foo get() {
   
return new Foo(this.someRuntimeString);
 
}
}


//if other code tried to inject either Foo or Provider<Foo> there should be a runtime error stating something like, instances of Foo must be obtained from the assisted inject factory FooFactory.class


I'll admit that in the absence of assisted params, @Provides becomes much more confusing if it's not also eligible to be injected in other contexts. I suppose you could allow it under such circumstances and only yell if assisted params are defined.

Anyway, clearly this feature request needs to be fleshed out a bit more. I don't really have the cycles to implement. Do you happen to know if a tracker exists where I could suggest this as a feature and keep an eye on it should it ever make its way into production?
Reply all
Reply to author
Forward
0 new messages