Binding Simple Pojos

480 views
Skip to first unread message

RayKrueger

unread,
Mar 13, 2007, 10:48:01 AM3/13/07
to google-guice
Do I really need to create a Provider for every simple getter/setter
based Pojo I wish to wire?
Put another way, Is there a simple way to bind all of the properties
on a given non-annotated pojo without writing a provider?

As a 10 minute test (25 minutes in now hehe), I'm converting a small
amount of Spring XML over to Guice. I don't see how I can get Guice to
wire existing spring classes (or my own for that fact) without writing
a Provider for every Pojo.

Kevin Bourrillion

unread,
Mar 13, 2007, 11:07:01 AM3/13/07
to google...@googlegroups.com
Hi Ray,

Can you put @Inject on your setters?

The annotation route and the Provider route are the two, uh, routes
that guice offers.

K

RayKrueger

unread,
Mar 13, 2007, 3:31:47 PM3/13/07
to google-guice
I hope this doesn't come over as a double-post, I never saw my first
reply get posted.

An inability to do basic dependency injection on existing Pojo/Beans;
is a pretty major limitation for anyone thinking of migrating even a
medium sized application to Guice. Especially if you're porting a
Spring based application and want to continue using the framework
classes like JmsTemplate, JdbcTemplate, HibernateTemplate.

Having to write a Provider for every Pojo is definitely not optimal.

On Mar 13, 10:07 am, "Kevin Bourrillion" <kevin...@gmail.com> wrote:
> Hi Ray,
>
> Can you put @Inject on your setters?
>
> The annotation route and the Provider route are the two, uh, routes
> that guice offers.
>
> K
>

Hani Suleiman

unread,
Mar 13, 2007, 3:38:59 PM3/13/07
to google...@googlegroups.com

On Mar 13, 2007, at 3:31 PM, RayKrueger wrote:

>
> I hope this doesn't come over as a double-post, I never saw my first
> reply get posted.
>
> An inability to do basic dependency injection on existing Pojo/Beans;
> is a pretty major limitation for anyone thinking of migrating even a
> medium sized application to Guice. Especially if you're porting a
> Spring based application and want to continue using the framework
> classes like JmsTemplate, JdbcTemplate, HibernateTemplate.
>
> Having to write a Provider for every Pojo is definitely not optimal.

Yes and no. Integration with third party stuff (eg, spring's classes)
is tricky because of the lack of injection ability into those
classes. So you can't for example wire up a Spring
PlatformTransactionManager and a Spring HibernateTemplate without
essentially subclassing them and creating annotated versions so they
can be wired up to each other.

However, Guice's job is not to wire up Spring's internals, you can
keep using Spring for those things. What you'd have to do is instead
is bind the spring dependencies in your code to guice. So for example:

configure()
{
//look up spring template bean
bind(JdbcTemplate.class).toInstance(springBean);
}

Then in your code you'd add in your @Inject annotations.

Yes, it does mean that you'll need to start adding annotations
everywhere in your POJOs. This is a *good* thing as your dependencies
are now explicitly specified in the source code, you don't have to go
to an xml file to figure out what gets added where (or alternatively,
hope that autowiring is set up correctly).

It does however mean that you still have the spring config file for
any spring *services* you need for integration. You just shouldn't
have any of your own beans in there.

Does this make sense?

Bob Lee

unread,
Mar 13, 2007, 3:41:24 PM3/13/07
to google...@googlegroups.com
On 3/13/07, RayKrueger <raykr...@gmail.com> wrote:
An inability to do basic dependency injection on existing Pojo/Beans;
is a pretty major limitation for anyone thinking of migrating even a
medium sized application to Guice. Especially if you're porting a
Spring based application and want to continue using the framework
classes like JmsTemplate, JdbcTemplate, HibernateTemplate.

Having to write a Provider for every Pojo is definitely not optimal.

Can you please provide some example Spring code which you would like to rewrite in Guice? I'm looking at the JmsTemplate docs ( http://www.springframework.org/docs/reference/jms.html), but they're not very clear. I am very familiar with JMS however.

Thanks,
Bob

RayKrueger

unread,
Mar 13, 2007, 3:56:38 PM3/13/07
to google-guice
Absolutely :)
The JmsTemplate is simply a convenience class for all the boiler plate
stuff you'd normally do with Jms. If all I wanted to do was use it to
publish messages I'd set it up like this in Spring 2.0...

<j2ee:jndi-lookup id="connectionFactory" jndi-name="java:/
ConnectionFactory"/>

<bean id="jmsTemplate"
class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestinationName" value="testQueue"/>
</bean>

I tried toying around with getting Guice to set up this class. Here's
what I started with...

bind(Context.class).to(InitialContext.class);

bind(ConnectionFactory.class)
.toProvider(JndiIntegration.fromJndi(ConnectionFactory.class,
"java:/ConnectionFactory"));

What I can't do now is ask Guice to wire the ConnectionFactory to the
JmsTemplate in any way. I can't get Guice to call
JmsTemplate.setConnectionFactory, and
JmsTemplate.setDefaultDestinationName.

Based on Hani's post I, can bind the JmsTemplate so that it can be
wired to @Inject annotated classes.
bind(JmsTemplate.class).toInstance(new JmsTemplate());

I just can't close the loop between the ConnectionFactory and the
JmsTemplate.

On Mar 13, 2:41 pm, "Bob Lee" <crazy...@crazybob.org> wrote:


> On 3/13/07, RayKrueger <raykrue...@gmail.com> wrote:
>
> > An inability to do basic dependency injection on existing Pojo/Beans;
> > is a pretty major limitation for anyone thinking of migrating even a
> > medium sized application to Guice. Especially if you're porting a
> > Spring based application and want to continue using the framework
> > classes like JmsTemplate, JdbcTemplate, HibernateTemplate.
>
> > Having to write a Provider for every Pojo is definitely not optimal.
>
> Can you please provide some example Spring code which you would like to

> rewrite in Guice? I'm looking at the JmsTemplate docs (http://www.springframework.org/docs/reference/jms.html), but they're not

Kevin Bourrillion

unread,
Mar 13, 2007, 4:01:34 PM3/13/07
to RayKrueger, google...@googlegroups.com
On 3/13/07, RayKrueger <raykr...@gmail.com> wrote:

> :( That was a resounding no.
>
> Guice can't wire standard beans/pojos. They have to be annotated, or
> you have to write a Provider for every existing Pojo you intend to
> bind. This is a pretty huge limitation for anyone attempting to
> migrate large -even medium- sized applications over from Spring (or
> any other framework) to Guice.

Now hold on there, you have lots of options. :-)

You can write one Provider class that uses reflection to inject your
setters based on your naming conventions. This custom Provider of
yours can have "@Inject Injector injector" which tells the Injector to
inject *itself* (does that blow your mind like it does mine?) and then
it can call injector.getInstance() to its heart's content. Then you
can bind as many types as you want to instances of that provider.

This isn't a fabulous solution, because guice will not have a complete
picture of your dependency graph. It will know only that these
providers depend on the Injector itself which means they could depend
on *anything* at runtime and Guice can't tell up front if you're doing
anything bogus.

Bob and I have both *thought* about allowing you to plug in custom
code that determines injection points for a class, so you could
override the default which uses the "look for all the members that
have @Inject" rule. We're not sure yet whether we want this, but if
it erases any "huge limitations" for you that no other feature would,
that's obviously a big plus.

K

>
>
> On Mar 13, 10:07 am, "Kevin Bourrillion" <kevin...@gmail.com> wrote:

> > Hi Ray,
> >
> > Can you put @Inject on your setters?
> >
> > The annotation route and the Provider route are the two, uh, routes
> > that guice offers.
> >
> > K
> >

RayKrueger

unread,
Mar 13, 2007, 4:07:32 PM3/13/07
to google-guice
That's where my first post went, directly to Kevin :P

Hani Suleiman

unread,
Mar 13, 2007, 4:11:32 PM3/13/07
to google...@googlegroups.com

On Mar 13, 2007, at 4:01 PM, Kevin Bourrillion wrote:

> Bob and I have both *thought* about allowing you to plug in custom
> code that determines injection points for a class, so you could
> override the default which uses the "look for all the members that
> have @Inject" rule. We're not sure yet whether we want this, but if
> it erases any "huge limitations" for you that no other feature would,
> that's obviously a big plus.
>

This is definitely worth having, as it eases the migration pain.

Kevin Bourrillion

unread,
Mar 13, 2007, 4:11:42 PM3/13/07
to RayKrueger, google...@googlegroups.com
btw, I wrote this before seeing Hani and Bob's replies and your
example code ... you should examine your specific example and find the
best solution. My email below really applies to the specific case, "I
need to inject into methods that aren't annotated, and I don't want to
write a bazillion providers." I think you can accomplish this with
some custom code, although our first hope is that you can arrange to
not need it. :-)

K

Hani Suleiman

unread,
Mar 13, 2007, 4:15:19 PM3/13/07
to google...@googlegroups.com

On Mar 13, 2007, at 3:56 PM, RayKrueger wrote:

>
> Absolutely :)
> The JmsTemplate is simply a convenience class for all the boiler plate
> stuff you'd normally do with Jms. If all I wanted to do was use it to
> publish messages I'd set it up like this in Spring 2.0...
>
> <j2ee:jndi-lookup id="connectionFactory" jndi-name="java:/
> ConnectionFactory"/>
>
> <bean id="jmsTemplate"
> class="org.springframework.jms.core.JmsTemplate">
> <property name="connectionFactory" ref="connectionFactory"/>
> <property name="defaultDestinationName" value="testQueue"/>
> </bean>
>
> I tried toying around with getting Guice to set up this class. Here's
> what I started with...

Ok, I think this is the problem here. I dont think guice should be
responsible for wiring spring content. Let spring wire up its own
components, Guice comes in when you have all these service objects
(*Template) already wired up by spring, and you expose them to guice
injected beans.

It's too much work and hassle to do all the spring internals wiring,
no point reinventing the wheel.

The main goal here is to have *your* code be cleaner and easier to
deal with, not Spring's. It's just too many contortions required to
wire Spring's internals to each other. Since you'e using JmsTemplate
here for example, your code doesn't need connectionFactory I'm
guessing, so no need to worry about that in guiceland at all. You
just have Spring work its autowiring magic just like it always did.

RayKrueger

unread,
Mar 13, 2007, 4:19:03 PM3/13/07
to google-guice
OK. You don't want to inject Spring's existing classes, that's not
really my point.

What about my own 30 existing Service classes, and my 50 Dao classes
for example?

I was just throwing out the Spring classes as an example, as it is the
obvious comparison that alot of people are going to look for right
now.

Hani Suleiman

unread,
Mar 13, 2007, 4:28:47 PM3/13/07
to google...@googlegroups.com

On Mar 13, 2007, at 4:19 PM, RayKrueger wrote:

>
> OK. You don't want to inject Spring's existing classes, that's not
> really my point.
>
> What about my own 30 existing Service classes, and my 50 Dao classes
> for example?

Yes, you do have to annotate those with @Inject.

I don't know what approach you have now, but it'll one of:

1) Autowiring: Magic happening for you, without explicit control of
what gets injected where. In your tests for example, you'd have to
modify your spring.xml to provide different implementations, and
stuff like having one test take in an implementation and another one
use a different one is tricky unless you're wiring by name. Wiring by
name is susceptible to typos and isn't very robust. Plus, with any
autowiring, you don't really have a good dependency graph, it's too
ad-hoc.

2) xml config: Switching to @Inject will make life infinitely more
pleasurable and your code so much more refactoring friendly, not to
mention how much more terse the configuration will be.


RayKrueger

unread,
Mar 13, 2007, 4:36:46 PM3/13/07
to google-guice
I'm hoping to find some good middle-ground here. Something that
doesn't involve me going through reams of existing code. Something
along the lines of what Kevin B had presented. Something that is
injected by reflection or some such idea.

Auto-wiring is bad, it's only good for "Hello World" type stuff most
of the time. Our apps are wired/injected by names, our tests validate
those arrangements. That works just fine :)
I'd love to see some way to tie the fancy Guice stuff into real-world
existing code. You guys are going to get comparisons to Spring all day
long, but it's really not about Spring. I write code too :)

Bob Lee

unread,
Mar 13, 2007, 5:37:46 PM3/13/07
to google...@googlegroups.com
I like Hani's suggestion of letting Spring do its thing, but if you really want to port the following Spring XML...


  <bean id="jmsTemplate"
        class="org.springframework.jms.core.JmsTemplate ">
     <property name="connectionFactory" ref="connectionFactory"/>
     <property name="defaultDestinationName" value="testQueue"/>
  </bean>

Using a custom provider is a little more verbose than Spring XML, but roughly equivalent. On the bright side, your IDE can generate much of the code for you.

  bind(JmsTemplate.class).toProvider(new Provider<JmsTemplate>() {
    @Inject ConnectionFactory connectionFactory;
    public JmsTemplate get() {
      JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
      jmsTemplate.setDefaultDestinationFactory("testQueue");  
    }
  });

Maybe we can shore this up some more when closures come out, but I don't have any more specific ideas.

As an alternative, you could extend JmsTemplate and bind to that:

  class InjectedJmsTemplate extends JmsTemplate {
    @Inject
    InjectedJmsTemplate(ConnectionFactory connectionFactory) {
      super(connectionFactory);
      setDefaultDestinationFactory("testQueue");
    }
  }

bind(JmsTemplate.class).to(InjectedJmsTemplate.class);

On 3/13/07, RayKrueger <raykr...@gmail.com> wrote
I'm hoping to find some good middle-ground here. Something that

doesn't involve me going through reams of existing code. Something
along the lines of what Kevin B had presented. Something that is
injected by reflection or some such idea.

I don't think there's any way around adding @Inject to your code. You might be able to automate the process somewhat, but using the annotation is what makes Guice great.

Bob

RayKrueger

unread,
Mar 13, 2007, 6:01:12 PM3/13/07
to google-guice
I definitely think that Guice can be a good framework. I would like to
use it on some projects coming up actually.
But, it really looks like Guice is limited to greenfield apps written
from scratch right now. You have to do things the Guice way from the
start, or you become a Provider writing machine :)

There's gotta be a good way. Like I was saying before, it's not just a
Spring question. What if I'm embedding Jetty and want to use Guice to
wire their classes together?
Do you guys intend the Guice framework to be used exclusively with
code that I control? Code that I own? Code that I can add the @Inject
annotation to?

> On 3/13/07, RayKrueger <raykrue...@gmail.com> wrote

Bob Lee

unread,
Mar 13, 2007, 6:46:12 PM3/13/07
to google...@googlegroups.com
On 3/13/07, RayKrueger <raykr...@gmail.com> wrote:
I definitely think that Guice can be a good framework. I would like to
use it on some projects coming up actually.
But, it really looks like Guice is limited to greenfield apps written
from scratch right now. You have to do things the Guice way from the
start, or you become a Provider writing machine :)

There's gotta be a good way. Like I was saying before, it's not just a
Spring question. What if I'm embedding Jetty and want to use Guice to
wire their classes together?
Do you guys intend the Guice framework to be used exclusively with
code that I control? Code that I own? Code that I can add the @Inject
annotation to?

We're open to new ideas. Right now, the custom provider example I posted doesn't look much worse than the Spring XML, and you get the benefit of auto-completion without needing specialized tools. Pretty much anything else I can think of resorts to string identifiers which I'd rather avoid.

Bob

Kevin Bourrillion

unread,
Mar 13, 2007, 8:24:49 PM3/13/07
to google...@googlegroups.com
On 3/13/07, RayKrueger <raykr...@gmail.com> wrote:

> I definitely think that Guice can be a good framework. I would like to
> use it on some projects coming up actually.
> But, it really looks like Guice is limited to greenfield apps written
> from scratch right now.

This makes me smile -- because most of our motivating use cases have
come from Google AdWords, which is millions of lines of code dating
back up to five years. For a while there it seemed like we would have
a tough time being able to virally spread it through our app without
having to make huge changes up front... but then pieces started really
clicking into place. So anyway, we are *anything* but greenfield. :-)


> You have to do things the Guice way from the
> start, or you become a Provider writing machine :)

I think you can often write generalized providers that can handle many
types of objects that share some common characteristics. E.g. today I
wrote a BeanInjectingProvider that injects setter methods (whether or
not they have @Inject). I did it just for the heck of it, and it was
pretty easy. I'll stick the code in com.google.inject.examples,
maybe, depending on what Bob thinks.


> There's gotta be a good way. Like I was saying before, it's not just a
> Spring question. What if I'm embedding Jetty and want to use Guice to
> wire their classes together?
> Do you guys intend the Guice framework to be used exclusively with
> code that I control? Code that I own? Code that I can add the @Inject
> annotation to?

Like I said, we've started by supporting two endpoints on a spectrum.
1. Provider: complete flexibility.
2. @Inject: convenience.

Now I've suggested an idea for a third point on the spectrum that
combines some flexibility with some convenience; this is the idea I
alluded to earlier, of customizing the way guice identifies the set of
injection points in a class. I'm looking into it.

You referred to your "own 30 existing Service classes and 50 Dao
classes"... can you remind me why you can't or don't want to put
@Inject on these?

K

RayKrueger

unread,
Mar 13, 2007, 9:27:44 PM3/13/07
to google-guice

On Mar 13, 7:24 pm, "Kevin Bourrillion" <kevin...@gmail.com> wrote:
> On 3/13/07, RayKrueger <raykrue...@gmail.com> wrote:
>
> > I definitely think that Guice can be a good framework. I would like to
> > use it on some projects coming up actually.
> > But, it really looks like Guice is limited to greenfield apps written
> > from scratch right now.
>
> This makes me smile -- because most of our motivating use cases have
> come from Google AdWords, which is millions of lines of code dating
> back up to five years. For a while there it seemed like we would have
> a tough time being able to virally spread it through our app without
> having to make huge changes up front... but then pieces started really
> clicking into place. So anyway, we are *anything* but greenfield. :-)

Yeah the greenfield thing was a dumb comment on my part. Disregard
that :P
I was really trying to get at starting from scratch, or migrating code
you own. My point is integration with 3rd party libraries.

>
> > You have to do things the Guice way from the
> > start, or you become a Provider writing machine :)
>
> I think you can often write generalized providers that can handle many
> types of objects that share some common characteristics. E.g. today I
> wrote a BeanInjectingProvider that injects setter methods (whether or
> not they have @Inject). I did it just for the heck of it, and it was
> pretty easy. I'll stick the code in com.google.inject.examples,
> maybe, depending on what Bob thinks.

Now you're talkin :)
Throw it up in a sandbox, I'd love to have a look at that.

>
> > There's gotta be a good way. Like I was saying before, it's not just a
> > Spring question. What if I'm embedding Jetty and want to use Guice to
> > wire their classes together?
> > Do you guys intend the Guice framework to be used exclusively with
> > code that I control? Code that I own? Code that I can add the @Inject
> > annotation to?
>
> Like I said, we've started by supporting two endpoints on a spectrum.
> 1. Provider: complete flexibility.
> 2. @Inject: convenience.
>
> Now I've suggested an idea for a third point on the spectrum that
> combines some flexibility with some convenience; this is the idea I
> alluded to earlier, of customizing the way guice identifies the set of
> injection points in a class. I'm looking into it.
>
> You referred to your "own 30 existing Service classes and 50 Dao
> classes"... can you remind me why you can't or don't want to put
> @Inject on these?
>
> K

Again, you're absolutely right. I own that code, I can annotate the
crap out of it :)

Bob mentioned an anonymous impl of Provider, it's funny because that
was the first thing I did on instinct.
It didn't seem right at first, but really, it's the same net effect as
the Spring XML file, it just happens to be a Java file instead. I'll
have to keep that in mind as I play with this stuff.

The comparisons of Spring and Guice are going to be interesting, but
really, I think they are truly different frameworks. I can't wait to
see what people come up with, that'll be fun.

Well, back to hacking!
-Ray

Hani Suleiman

unread,
Mar 13, 2007, 9:37:45 PM3/13/07
to google...@googlegroups.com
On Mar 13, 2007, at 9:27 PM, RayKrueger wrote:

>>
>> You referred to your "own 30 existing Service classes and 50 Dao
>> classes"... can you remind me why you can't or don't want to put
>> @Inject on these?
>>
>> K
>
> Again, you're absolutely right. I own that code, I can annotate the
> crap out of it :)
>

Yeah this is what I couldn't understand, adding even a few hundred
@Inject annotations to all your classes is trivial and brainless
work, a couple of hours at most to switch fully to this syntax (doing
the whole thing in spring xml is likely to take at least twice as long!)

Is there a more conceptual/functional objection that the effort to do
it?

Ray Krueger

unread,
Mar 13, 2007, 10:21:42 PM3/13/07
to google...@googlegroups.com

Nah, I'm good now I think.

You guys really are making the Spring XML out to be worse than it is :)
It's all fine and dandy with a good ide like IDEA.

>
> >
>

Hani Suleiman

unread,
Mar 13, 2007, 10:25:29 PM3/13/07
to google...@googlegroups.com
On Mar 13, 2007, at 10:21 PM, Ray Krueger wrote:

> You guys really are making the Spring XML out to be worse than it
> is :)
> It's all fine and dandy with a good ide like IDEA.

Well...yes!

I've never understood how it makes sense to have information that's
tightly coupled to the source be held away from it. We all laugh at
ejb2's descriptors, where method names go into xml for all security
permissions, tx behaviour, etc. Why is it OK when Spring does it?

Just because that was the state of the art and the only way to do
metadata in 2001 is no reason to keep doing it that way forever. We
have a better way of doing it now. It sucks for those who can't use
it (ie, Spring, since it has to support 1.3) but for those of us with
the luxury of something more civilised, why on earth would you mix
source and xml?


Ray Krueger

unread,
Mar 13, 2007, 10:27:06 PM3/13/07
to google...@googlegroups.com
On 3/13/07, Hani Suleiman <ha...@formicary.net> wrote:
>

I never said I liked the XML :P
>
>
> >
>

ajoo....@gmail.com

unread,
Mar 14, 2007, 12:49:28 AM3/14/07
to google-guice

> I think you can often write generalized providers that can handle many
> types of objects that share some common characteristics. E.g. today I
> wrote a BeanInjectingProvider that injects setter methods (whether or
> not they have @Inject). I did it just for the heck of it, and it was
> pretty easy. I'll stick the code in com.google.inject.examples,
> maybe, depending on what Bob thinks.
>

It'd be nice to see how it gets implemented. To me what's difficult is
not using reflection to call setters. It is how I can still ask Guice
to inject the dynamically detected dependencies to the
BeanInjectingProvider. Doesn't Guice exclusively depend on static meta-
data to detect dependencies?

Bob Lee

unread,
Mar 14, 2007, 12:52:52 AM3/14/07
to google...@googlegroups.com
To me what's difficult is
not using reflection to call setters. It is how I can still ask Guice
to inject the dynamically detected dependencies to the
BeanInjectingProvider. Doesn't Guice exclusively depend on static meta-
data to detect dependencies?

No, you can push everything to runtime if you like. We just prefer static dependencies so we can check it all at startup and give you more than one error message at a time.

Bob

ajoo....@gmail.com

unread,
Mar 14, 2007, 12:57:24 AM3/14/07
to google-guice
Let me guess. Do you mean that I can @Inject a Injector into the
Provider and start dynamic dependency from there?

If true, that is a surprisingly nice workaround.

Kevin Bourrillion

unread,
Mar 14, 2007, 12:57:28 AM3/14/07
to google...@googlegroups.com
I don't think I fully understod your question.  Right now Guice does have only one way to *detect* dependencies, which is @Inject.  Providing any other way was the subject of my next paragraph in this email which you didn't quote. :-)  By all means let me know where we're disconnected here.

Looking at Bob's response that just came in -- I think we could all stand to be a little more explicit about what we mean by "static dependencies" and "static metadata to detect dependencies" and so on and so forth, since I don't think we're nearly at the point where everyone intrinsically shares the same vocabulary for these ideas that are new to a lot of us.

K


Kevin Bourrillion

unread,
Mar 14, 2007, 12:58:40 AM3/14/07
to google...@googlegroups.com
:-)  I hope it's first in a long line of nice surprises about Guice!

K


ajoo....@gmail.com

unread,
Mar 14, 2007, 1:06:40 AM3/14/07
to google-guice
Probably an example will do a better job in explaining.

This is my guessed version of "dynamically detected dependency":
<pre>
class BeanInjectingProvider<T> implements Provider<T> {
@Inject Injector injector; //if it is allowed to inject an injector.
public T get() {
T instance = ...; //however I get this instance.
for(property: all properties found in class T) {
Class propType = property.getType();
Object propValue = injector.getInstance(propType);
property.getWriteMethod().invoke(instance, new Object[]
{propValue});
}
return instance;
}
}
</pre>

And by static meta data, I mean one has to declare all the required
dependencies statically as in:
<pre>
class BeanXYZProvider implements Provider<BeanXYZ> {
@Inject
public BeanXYZProvider (Dep1 dep1, Dep2 dep2) {...}
public BeanXYZ get() {
BeanXYZ instance = ...;
instance.setDep1(dep1);
instance.setDep2(dep2);
}
}
</pre>

In the latter version, I have to statically know all the dependencies
that BeanXYZ needs in order to create an injectable constructor for
the provider, which means it cannot be a "generic" provider.

Kevin Bourrillion

unread,
Mar 14, 2007, 1:10:37 AM3/14/07
to google...@googlegroups.com
Your first bit of code is very close to my implementation I started this afternoon!  I'll share it tomorrow.  And yes, if the second example were all that could be done, we would indeed all be "Provider-writin' fools"... :-)

K


ajoo....@gmail.com

unread,
Mar 14, 2007, 1:28:24 AM3/14/07
to google-guice
Indeed, if Injector is injectable, we can do a lot of dynamic tricks.
(including the static factory method injection that I was talking
about in another thread. Though it will still be more consistent with
Guice's static typed philosophy if Guice by default scans static
factory methods when an injectable constructor is not found.)


Kevin Bourrillion

unread,
Mar 15, 2007, 5:55:49 PM3/15/07
to google...@googlegroups.com
> I think you can often write generalized providers that can handle many
> types of objects that share some common characteristics.   E.g. today I
> wrote a BeanInjectingProvider that injects setter methods (whether or
> not they have @Inject).  I did it just for the heck of it, and it was
> pretty easy.  I'll stick the code in com.google.inject.examples ,
> maybe, depending on what Bob thinks.

It'd be nice to see how it gets implemented.

Ok, here you go.  Admittedly, it was a little less "easy" than I was thinking it was.

This is just sample code... tested moderately.  You can do whatever you want with it.


/**
 * Copyright (C) 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.inject.example ;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider ;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

/**
 * A provider which injects the instances it provides using an "auto-wiring"
 * approach, rather than requiring {@link Inject @Inject} annotations.  This
 * provider requires a Class to be specified, which is the <i>concrete</i>
 * type of the objects to be provided.  It must be hand-instantiated by your
 * {@link com.google.inject.Module}, or subclassed with an injectable
 * constructor (often simply the default constructor).
 *
 * <p>Examples:
 *
 * <pre>
 *     binder.bind(Bob.class)
 *         .toProvider(new AutowiringProvider&lt;Bob>(Bob.class));</pre>
 *
 * or
 *
 * <pre>
 *     binder.bind(Bob.class).toProvider(BobProvider.class);</pre>
 *
 * ... where {@code BobProvider} is ...
 *
 * <pre>
 *     public static class BobProvider extends AutowiringProvider&lt;Bob> {
 *       public BobProvider() {
 *         super(Bob.class);
 *       }
 *     }</pre>
 *
 * @author Kevin Bourrillion (kev...@google.com)
 */
public class AutowiringProvider<T> implements Provider<T> {

  private final Class<? extends T> concreteClass;
  private final Set<Method> allSetterMethods;

  /*
   * Guice will perform field and method injection for any Provider instances
   * that are bound using bind(type).toProvider(providerInstance).
   */
  protected @Inject Injector injector;

  public AutowiringProvider(Class<? extends T> concreteClass) {
    validateClass(concreteClass);
    this.concreteClass = concreteClass;
    this.allSetterMethods = findAllSetterMethods(concreteClass);
  }

  public T get() {
    T instance = newInstance(concreteClass);
    for (Method setterMethod : allSetterMethods) {
      inject(instance, setterMethod);
    }
    return instance;
  }

  /*
   * You can emulate @Inject(optional = true) for all your setters by
   * overriding this method to enclose it in a try/catch of RuntimeException,
   * and ignoring or logging the exception.
   */
  protected void inject(Object instance, Method setterMethod) {
    Class<?> type = setterMethod.getParameterTypes()[0];
    Object dependency = injector.getInstance(type);
    try {
      setterMethod.invoke(instance, dependency);
    }
    catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
    catch (InvocationTargetException e) {
      throw new RuntimeException(e.getCause());
    }
  }

  private static <T> void validateClass(Class<? extends T> type) {
    int modifiers = type.getModifiers();
    if (Modifier.isAbstract(modifiers)) {
      throw new IllegalArgumentException("abstract type: " + type);
    }
    if (!Modifier.isPublic(modifiers)) {
      throw new IllegalArgumentException("class is not public: " + type);
    }
  }

  private static Set<Method> findAllSetterMethods(Class<?> type) {
    Set<Method> setters = new HashSet<Method>();
    BeanInfo beanInfo;
    try {
      beanInfo = Introspector.getBeanInfo(type);
    }
    catch (IntrospectionException e) {
      throw new RuntimeException(e);
    }
    for (PropertyDescriptor prop : beanInfo.getPropertyDescriptors()) {
      Method method = prop.getWriteMethod();
      if (method != null) {
        setters.add(method);
      }
    }
    return setters;
  }

  private static <T> T newInstance(Class<T> type) {
    try {
      return type.newInstance();
    }
    catch (Exception e) { // Class.newInstance() can throw anything!
      throw new RuntimeException(e);
    }
  }
}

K

Reply all
Reply to author
Forward
0 new messages