How can I pass a parameter for a provider?

7,868 views
Skip to first unread message

zhaoyi

unread,
Aug 13, 2009, 9:27:35 PM8/13/09
to google-guice
Below is my code. When I running this program, I will get an error
"Could not find a suitable constructor in java.lang.Integer. Classes
must have either one (and only one) constructor annotated with @Inject
or a zero-argument constructor that is not private.". How can I pass a
parameter to the provider?

thanks.

public class ProviderDemo {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule1());
Interface1 in = injector.getInstance(Interface1.class);
System.out.println(in);
}


}

class MyModule1 extends AbstractModule{
@Override
protected void configure() {

}

@Provides
public Interface1 provideInterface1(int type){
if(type == 1){
return new Imple1();
}else if(type ==2){
return new Imple2();
}
return null;
}

}

interface Interface1{
public void sayHello();
}

class Imple1 implements Interface1{
@Override
public void sayHello() {
System.out.println("imple 1");
}
}

class Imple2 implements Interface1{
@Override
public void sayHello() {
System.out.println("imple 2");
}
}

limpb...@gmail.com

unread,
Aug 13, 2009, 11:10:36 PM8/13/09
to google-guice
On Aug 13, 6:27 pm, zhaoyi <zhaoyi0...@gmail.com> wrote:
> Below is my code. When I running this program, I will get an error
> "Could not find a suitable constructor in java.lang.Integer. Classes
> must have either one (and only one) constructor annotated with @Inject
> or a zero-argument constructor that is not private.". How can I pass a
> parameter to the provider?

Instead of using a provider, write a regular factory class that
provides the requested value. Although you must code the factory by
hand, you can inject values into it. For example,

public class ImplFactory {
@Inject Provider<Imple1> imple1Provider;
@Inject Provider<Imple2> imple2Provider;

public Interface1 create(int type) {
return type == 1 ? imple1Provider.get() : imple2Provider.get();
}
}

In your client code, simply inject this factory.

zhaoyi

unread,
Aug 13, 2009, 11:16:00 PM8/13/09
to google-guice
If I use my Factory class, why do I need to use guice to inject the
provider? Is there a benefit for this?

Miroslav Genov

unread,
Aug 14, 2009, 2:57:22 AM8/14/09
to google...@googlegroups.com

Max Bowsher

unread,
Aug 14, 2009, 8:09:22 AM8/14/09
to google...@googlegroups.com
zhaoyi wrote:
> Below is my code. When I running this program, I will get an error
> "Could not find a suitable constructor in java.lang.Integer. Classes
> must have either one (and only one) constructor annotated with @Inject
> or a zero-argument constructor that is not private.". How can I pass a
> parameter to the provider?

Hi zhaoyi,

To answer your direct question, passing a parameter to a provider
invocation is explained here:
http://code.google.com/p/google-guice/wiki/AssistedInject


However, if your provider simply switches the returned implementation
based on a parameter, I think you should instead be writing two separate
providers and employing binding annotations as described here:
http://code.google.com/p/google-guice/wiki/BindingAnnotations


It would be easier to suggest an appropriate technique if you made your
example code a little less abstract.


Max.

signature.asc

Rick

unread,
Aug 22, 2009, 9:59:34 PM8/22/09
to google...@googlegroups.com
On Fri, Aug 14, 2009 at 8:09 AM, Max Bowsher<ma...@f2s.com> wrote:
>
> To answer your direct question, passing a parameter to a provider
> invocation is explained here:
> http://code.google.com/p/google-guice/wiki/AssistedInject

(I know I posted this question in a different way in another recent
thread but it make more sense in this one.)
I'm still confused by this. In the example in the docs here for a Provider:

http://code.google.com/p/google-guice/wiki/ProviderBindings

How would you have different connection objects injected in that
constructor for the Provider. Sorry if this is totally newb, but I
don't get it.

The example then shows

public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class)
.toProvider(DatabaseTransactionLogProvider.class);
}

What I want to do is be able to do something like (Just using the
example above for illustration, by classes are different):

//ClassA has
public void setTransactionLog(@Named("FooBar") TransactionLog transactionLog)

//ClassB has
public void setTransactionLog(@Named("Whatever") TransactionLog transactionLog)

and be able to somehow have the "FooBar" version have a different
connection than the "Whatever" version?

In my case I want to load "FooBar" and "Whatever" versions of the
provider with a different String (path to a resource file), but
stumped how to set it up I thought I could do something like:.

MyProvider myProvider = new MyProvider("file.xml");
bind(ResultOfProvider.class).annotatedWith(Names.named("FooBar")).toProvider(myProvider);

But the above doesn't seem to work. I'm probably missing something
really fundamental here, so thanks in advance.

Max Bowsher

unread,
Aug 24, 2009, 8:12:34 AM8/24/09
to google...@googlegroups.com


What you're doing above seems reasonable to me - you'll need to
elaborate on "doesn't seem to work" to get help.

Max.

signature.asc

Rick

unread,
Aug 24, 2009, 11:11:53 AM8/24/09
to google...@googlegroups.com
On Mon, Aug 24, 2009 at 8:12 AM, Max Bowsher <ma...@f2s.com> wrote:
 
What you're doing above seems reasonable to me - you'll need to
elaborate on "doesn't seem to work" to get help. 

Thanks Max for your comments...

As far as "not working" what I end up with is "sqlSession" never being bound. Code to illustrate::

For example this DOES work fine:

//SqlSessionProvider modified with default constructor (resource file hardcoded in Provider)

//Module:
bind(SqlSession.class).toProvider(SqlSessionProvider.class);

//Implementation - WORKS
@Inject
public void setSqlSession(SqlSession sqlSession) {
    System.out.println("!!!!!! MyDbIbatisDao setSqlSession");
    this.sqlSession = sqlSession;
}

------------------
This ends up with sqlSession never being bound:

//SqlSessionProvider modified has constructor, takes resource file name

//Module:
SqlSessionProvider myDbProvider = new SqlSessionProvider("mydb-ibatis-config.xml");
bind(SqlSession.class).annotatedWith(Names.named("MyDB")).toProvider(myDbProvider);

//Implementation - NEVER CALLED
@Inject
public void setSqlSession(@Named("MyDB") SqlSession sqlSession) {
    System.out.println("!!!!!! MyDbIbatisDao setSqlSession");
    this.sqlSession = sqlSession;
}


In this later case, I never see "setSqlSession" called (and obviously my Provider get thus never called either.)
Am I declaring my setter incorrectly with the named annotation? I've even tried with field injection and no luck either.

@Inject @Named("MyDB")
protected SqlSession sqlSession;

Stuart McCulloch

unread,
Aug 24, 2009, 12:03:31 PM8/24/09
to google...@googlegroups.com
2009/8/24 Rick <ric...@gmail.com>

probably a silly question, but that annotation is com.google.inject.name.Named right?


--
Cheers, Stuart

Rick

unread,
Aug 24, 2009, 1:40:54 PM8/24/09
to google...@googlegroups.com
On Mon, Aug 24, 2009 at 12:03 PM, Stuart McCulloch <mcc...@gmail.com> wrote:
 
This ends up with sqlSession never being bound:

//SqlSessionProvider modified has constructor, takes resource file name

//Module:
SqlSessionProvider myDbProvider = new SqlSessionProvider("mydb-ibatis-config.xml");
bind(SqlSession.class).annotatedWith(Names.named("MyDB")).toProvider(myDbProvider);

//Implementation - NEVER CALLED
@Inject
public void setSqlSession(@Named("MyDB") SqlSession sqlSession) {
    System.out.println("!!!!!! MyDbIbatisDao setSqlSession");
    this.sqlSession = sqlSession;
}

In this later case, I never see "setSqlSession" called (and obviously my Provider get thus never called either.)
Am I declaring my setter incorrectly with the named annotation? I've even tried with field injection and no luck either.

@Inject @Named("MyDB")
protected SqlSession sqlSession;

probably a silly question, but that annotation is com.google.inject.name.Named right?

 

Yes:


import com.google.inject.name.Named;
import com.google.inject.Inject;

 

Rick

unread,
Aug 24, 2009, 2:21:13 PM8/24/09
to google...@googlegroups.com
GAHHHHH what a MORON I am!!! I didn't realize I was also doing

@Inject
SqlSession sqlSession;

In another test and of course that was blowing up because I wasn't passing the @Name.

Sorry for your time.  At least I hope this is an ok way to pass data to a provider in a Module, because it's working now:


SqlSessionProvider myDbProvider = new SqlSessionProvider("mydb-ibatis-config.xml");
bind(SqlSession.class).annotatedWith(Names.named("MyDB")).toProvider(myDbProvider);




--
Rick R

Max Bowsher

unread,
Aug 24, 2009, 2:25:27 PM8/24/09
to google...@googlegroups.com
Rick wrote:
> On Mon, Aug 24, 2009 at 8:12 AM, Max Bowsher <ma...@f2s.com
> <mailto:ma...@f2s.com>> wrote:
>
>
> What you're doing above seems reasonable to me - you'll need to
> elaborate on "doesn't seem to work" to get help.
>
>
> Thanks Max for your comments...
>
> As far as "not working" what I end up with is "sqlSession" never being
> bound. Code to illustrate::

[snip]

> In this later case, I never see "setSqlSession" called (and obviously my
> Provider get thus never called either.)

I see nothing wrong with the above code, so.... when all else fails,
construct a simple example that someone else can run to demonstrate the
problem.

Here's a single .java source file which demonstrates something like what
you want:

=======================================================================
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import com.google.inject.name.Names;


public class TrivialExample {


public static void main(String[] args) {

Guice.createInjector(
new FooModule()).getInstance(Injectable.class);
}
}

class Foo {
public Foo() {
System.out.println("New object constructed: " + this);
}
}

class FooProvider implements Provider<Foo> {
public FooProvider(String initThing) {
System.out.println("FooProvider created with initThing: "
+ initThing);
}

@Override
public Foo get() {
return new Foo();
}
}

class FooModule extends AbstractModule {
@Override
protected void configure() {
bind(Foo.class).annotatedWith(Names.named("wibble"))
.toProvider(new FooProvider("boing!"));
}
}

class Injectable {
@Inject
public void setSqlSession(@Named("wibble") Foo foo) {
System.out.println("Injectable injected with: " + foo);
}
}
=======================================================================

Run it, for me it *does* print "Injectable injected with: ..."

If the above doesn't give you inspiration for what might be wrong, boil
your non-working case down to a similarly small example, and post it here.

Max.

signature.asc
Reply all
Reply to author
Forward
0 new messages