thoughts on Guice

242 views
Skip to first unread message

James Strachan

unread,
Mar 15, 2007, 12:38:10 PM3/15/07
to google...@googlegroups.com
I just thought I'd post my immediate feedback from having a noodle at
the docs and code. So far I'm liking lots of Guice; I like the way
modules and bindings work and the use of providers or annotations can
be used etc.


POJO Developer Contract and Bean Support
===================================
My first (unfortunately kinda lengthly) ramble is about the POJO
developer contract. i.e. what things must/should a developer do to
make POJOs work nicely with Guice (while also considering the universe
outside of Guice too).

As a bit of background, I work on a number of projects; none of which
can really mandate which IoC container is used. (I suspect lots of
folks are in that camp). So I write POJOs which can be used by
plan-old-Java-code (POJC? :) or can be used in Spring, EJB3, Pico,
HiveMind et al. It'd be good if the POJOs I work on could be used by
folks using Guice too without too much unnecessary
boilerplate/provider code.

One of the great benefits of IoC is that the framework is unobtrusive;
ideally completely invisible. So the end user can use your code in
pure Java or with Guice or Spring or whatnot. Admittedly adding an
@Inject annotation to every constructor, field or injection method is
not that intrusive, but it is another jar dependency (and even though
this might not seem a big deal to some folks, say working on a massive
in-house web app, but for other folks its a big deal).

After working a fair bit with various IoC frameworks from Pico to
Spring to HiveMind, my previous 'good behaving POJO' practice was...

* have good constructors which take the mandatory dependencies (then
even a POJC guy is totally aware of the real mandatory dependencies)
* use bean properties for optional things
* sometimes have zero argument constructors and bean properties for
mandatory dependencies (which is just a hack to play nicely with
configure-properties-by-name in XML/LDAP/properties files since Java
doesn't deal with parameter names well)

The options of injection in general break down to

* field injection
* method injection
* constructors
* setter injection (a subset of method injection really)

FWIW I'm not a fan of field level injection personally, as it
basically means normal Java code can't use the POJO and only magic
frameworks or reflection ninja can create an instance, so I try avoid
it at all costs (though yes it does save on a few lines of boiler
plate IDE generated code). Incidentally as someone who likes their
code to be reusable by a wide variety of tools and frameworks, I see
no great gain by explicitly making POJOs not be Java Beans too just
because we have annotations; so if using method injection, I'd make
'em a bean setter too then some bean-based tool/framework/library can
work nicely with the POJO as well as guicy stuff.

From the docs it appears that the guice-way is to always use an
@Inject on constructors. From a quick noodle at the code it does
appear constructor injection is only supported when the @Inject
annotation is used and only one constructor can have an @Inject
annotation right? (Excuse me if I've misread the code, I only had a
quick looksie). Is this really a design decision? If so then it does
seem pretty restrictive to me. There's a ton of objects which could
easily be inject-able with Guice but which due to this @Inject
limitation means folks have to create tons of silly boilerplate code
deriving from classes (if they're not final that is) and adding
annotations to the constructors you wanna use; or writing providers.

Similarly at first look it seems that Guice has no default out of the
box support for injecting into bean properties unless they have
@Inject on them. Given the zillion beans out there, it seems strange.

Now clearly @Inject is required for field and method injection.
However I don't see why its necessary for constructors or bean
properties. In many ways it'd be good to kinda think of constructors
as being mandatory injection points (so kinda having a default
@Inject(optional=false) on them if none is specified). Similarly all
bean setters could be considered to have @Inject(optional=true). Then
any Java Bean code could be used nicely with Guice without having to
hand-craft derived classes-with-annotations or writing custom
providers etc.

If there are many constructors and you want to give Guice a hint which
constructor to use, then sure use an annotation; but I don't see why
they are necessary on every constructor. i.e. a smart default could
be, if there are no @Inject annotations, then assume they all kinda
have @Inject(optional=false) on them and choose the one with the most
arguments which can be completely resolved - if in doubt barf with a
good error message.

I realise this is a bit more work for the Guice framework; to choose
constructors and detect bean properties and so forth; but I'd rather
my IoC framework did a bit more clever work for me than me have to do
tons of mindless boilerplate code to take 3rd party or legacy POJOs
and make 'em guicy. BTW am liking that adjective "guicy" :)


Lifecycles
==========
I didn't see any particular lifecycle stuff, maybe I missed it. Pretty
much every other IoC container I've used had the concept of pre and
post lifecycle methods / annotations. e.g. in EJB3 its @PostConstruct
and @PreDestroy (which I always get confused about, would have
preferred @Start and @Stop :). In Spring its an interface
InitializingBean and DisposableBean. These are very common ways to add
a hook that after the Injection has occurred, call a method to
validate the bean is fine and start things off. e.g. its quite common
to have optional injection points but which some combination of
optional properties/fields have to be configured just so for a valid
configuration. So the start hook is just a way of giving the POJO
developer a chance to validate itself.

So having some kind of @Start / @Stop callback methods would be good
in Guice. Maybe they're in there somewhere but I couldn't see them.
(As as aside, as the Pico folks found, the great benefit of
constructor injection is that there's no big need for a separate
lifecycle method call as its one atomic constructor).


Avoiding The Hard Guice JAR Dependency
==================================
Whatever annotations are used to indicate injection points (whether
@Inject from Guice, or @Resource from EJB3 or the Spring ones or
whatever else comes out of the various JSRs) along with lifecycle APIs
like Spring's InitializingBean or EJB3s @PostConstruct & @PreDestroy
or those SCA ones which I've never totally understood yet, it would be
good to be able to write POJOs so that they work in various
containers, but have no extra hardwired jar dependencies.

e.g. there's no way I'm gonna write code in say, ActiveMQ, to bind
core classes to Spring, Guice or EJB3 (though I might provide some
extension classes which aid integration in places). However from the
POJO developers perspective, its just some simple metadata which
should be reusable in each framework.

I've seen lots of libraries do the same thing where they make their
own lifecycle APIs up rather than force a dependency on
spring/ejb3/guice etc.

One idea is for a library like Guice to be able to work with external
annotations to avoid the rather unfortunate jar-dependency issue of
Java annotations.

e.g. in ActiveMQ I could define org.apache.activemq.Inject to add the
metadata of the injection points in ActiveMQ code and to avoid any
runtime dependencies on Guice. Then we could easily then map this
annotation to the Guice framework in a non-hard dependency manner. For
example Guice could look for
META-INF/services/com/google/guice/annotations files which could be a
little properties file describing what local aliases of the
@Inject/@PostConstruct/@PreDestroy annotations are being used by a
library and auto-wire them.

Mostly they are pretty trivial annotations to mark an injection point
(and indicate the manadatory/optional flag) or mark the start/stop
lifecycle method, so it would be very easy to write a really simple
mechanism to allow Guice to work with, say, POJOs with the existing
EJB3 annotations or SCA or Spring etc.

e.g. It'd be really cool if out of the box Guice mapped EJB3's
@Resource to @Inject(optional=false) and ditto for Spring & SCA
annotations etc

Right now the only real criticism (other than bean support) of Guice
is the runtime jar intrusion - which definitely is a barrier to
adoption. Not everyone can work on a big inhouse web-app where adding
another jar in the WEB-INF/lib directory is no biggie :). So adding
this fairly simple pluggable annotation support could really help.

Anyway, please excuse my rather long ramble. Keep up the good work on
Guice and I'll try to create more concise and focussed posts in future
:)

--

James
-------
http://radio.weblogs.com/0112098/

Hani Suleiman

unread,
Mar 15, 2007, 12:45:44 PM3/15/07
to google...@googlegroups.com
Interestingly, I've filed issues for some of the things you mentioned:

- Lifecycle support for JSR-250 annotations
- Mapping @Resource to @Inject

Kevin also has a bean provider that will autowire beans without
annotations.

On Mar 15, 2007, at 12:38 PM, James Strachan wrote:

<snipped lots of good stuff>

Ben

unread,
Mar 15, 2007, 1:02:51 PM3/15/07
to google...@googlegroups.com
I like the constructor by default is @Inject idea. Though not sure if
we want to make Guice pick a ctor among many (that sounds a bit too
smart and not deterministic to me).

peter royal

unread,
Mar 15, 2007, 1:12:34 PM3/15/07
to google...@googlegroups.com
On Mar 15, 2007, at 10:02 AM, Ben wrote:
> I like the constructor by default is @Inject idea. Though not sure if
> we want to make Guice pick a ctor among many (that sounds a bit too
> smart and not deterministic to me).

To share what Picocontainer does..

It starts with the cxtor with the most arguments, tries to satisfy
that, and then works down cxtors with fewer and fewer arguments
seeing if it can satisfy any of those before saying it can't
construct the component.

In actuality, its a feature I've never utilized, only ever having one
cxtor.

The other nice "magic" thing it does with cxtors is if you declare Foo
[] as a param, it globs up all instances of Foo in the container and
passes them in (except for the current class, in case its an instance
of Foo)

-pete

--
(peter.royal|osi)@pobox.com - http://fotap.org/~osi

James Strachan

unread,
Mar 15, 2007, 1:22:33 PM3/15/07
to google-guice
On Mar 15, 5:02 pm, Ben <ajoo.em...@gmail.com> wrote:
> I like the constructor by default is @Inject idea. Though not sure if
> we want to make Guice pick a ctor among many (that sounds a bit too
> smart and not deterministic to me).

FWIW Pico and Spring both do this. Again it comes down to the delicate
balance between how much work the framework does for you and how much
boilerplate code the application developer has to do to get the
framework to do what they want. So long as its a simple unambiguous
rule that solves the most common cases - like use the constructor with
the most arguments by default if there are no annotations; if there
are multiple possible constructors with the same number of parameters
then fail with a nice error message informing the user to either add
an annotation or custom provider to disambiguate.

Ben

unread,
Mar 15, 2007, 2:06:55 PM3/15/07
to google...@googlegroups.com
Yes. I understand that. But I never feel comfortable with this feature
of Spring.

It might cause surprises. Suppose I have a class and it is injected by
Guice. Everything works fine until some developer adds another
constructor. This change itself looks quite innocent. Common sense
tells me that adding a new method/ctor will not break existing code
(at least when the compiler does not complain).

Personally I feel more comfortable without such intelligence built-in
the container. I'd rather to use annotation to disambiguate
explicitly.

Yes, practically it might has its convenience side. But simply adding
a @Inject annotation is quite convenient already.


Ben.

On 3/15/07, James Strachan <james.s...@gmail.com> wrote:
>

Kevin Bourrillion

unread,
Mar 15, 2007, 2:39:05 PM3/15/07
to google...@googlegroups.com
On 3/15/07, James Strachan <james.s...@gmail.com> wrote:

I just thought I'd post my immediate feedback from having a noodle at
the docs and code. So far I'm liking lots of Guice; I like the way
modules and bindings work and the use of providers or annotations can
be used etc.

Your feedback is most excellent!


FWIW I'm not a fan of field level injection personally, as it
basically means normal Java code can't use the POJO and only magic
frameworks or reflection ninja can create an instance, so I try avoid
it at all costs (though yes it does save on a few lines of boiler
plate IDE generated code).

Strangely I never even really thought about that (since I just tend to not use it anyway).  You're right, field injection is totally wack.
 

Incidentally as someone who likes their
code to be reusable by a wide variety of tools and frameworks, I see
no great gain by explicitly making POJOs not be Java Beans too just
because we have annotations; so if using method injection, I'd make
'em a bean setter too then some bean-based tool/framework/library can
work nicely with the POJO as well as guicy stuff.

 

From the docs it appears that the guice-way is to always use an
@Inject on constructors. From a quick noodle at the code it does
appear constructor injection is only supported when the @Inject
annotation is used and only one constructor can have an @Inject
annotation right?

That's right.  It looks for a unique injectable constructor, then if that's not found, expects a default constructor.


Is this really a design decision? If so then it does
seem pretty restrictive to me. There's a ton of objects which could
easily be inject-able with Guice but which due to this @Inject
limitation means folks have to create tons of silly boilerplate code
deriving from classes (if they're not final that is) and adding
annotations to the constructors you wanna use; or writing providers.

I've just filed issue 71 which I hope will address this to your satisfaction.
 

Similarly at first look it seems that Guice has no default out of the
box support for injecting into bean properties unless they have
@Inject on them. Given the zillion beans out there, it seems strange.

Right -- issue 71 again.
 

Now clearly @Inject is required for field and method injection.
However I don't see why its necessary for constructors or bean
properties. In many ways it'd be good to kinda think of constructors
as being mandatory injection points (so kinda having a default
@Inject(optional=false) on them if none is specified).

Right now, I believe that the out-of-the-box behavior of Guice will *always* be that it will never call anything on your code that doesn't have @Inject on it (apart from a default constructor).  We are trying to be careful about the amount of "magic".  You should be able to look at any method not in your public API that has no callers according your IDE, and has no annotations on it that describe how it can be used reflectively, and you should know that that's an unused method and you can delete it.  I think to not require that annotation is semi-evil from that perspective.


If there are many constructors and you want to give Guice a hint which
constructor to use, then sure use an annotation; but I don't see why
they are necessary on every constructor. i.e. a smart default could
be, if there are no @Inject annotations, then assume they all kinda
have @Inject(optional=false) on them and choose the one with the most
arguments which can be completely resolved - if in doubt barf with a
good error message.

I have thought some about the value of letting Guice choose from among alternative constructors.   But I couldn't come up with a rule for choosing one that felt satisfactory to me.  The most resolvable arguments... it feels unpleasantly nondeterministical.  Anyway, though, as I was hacking up AdWords code to get it all guicy, there was a point when this idea did come up as being something possibly useful -- though I easily managed to not need it.  As usual, when deciding whether to add a feature or not, the thing that helps the most is if anyone can come up with a dynamite use case for us.  Sometimes even one is all it takes if it's a really good one.  Without that, deciding is harder.


I realise this is a bit more work for the Guice framework; to choose
constructors and detect bean properties and so forth; but I'd rather
my IoC framework did a bit more clever work for me than me have to do
tons of mindless boilerplate code to take 3rd party or legacy POJOs
and make 'em guicy. BTW am liking that adjective "guicy" :)

I think our goal is to keep guice as simple as possible, but no simpler.  Where "possible" is unfortunately defined very vaguely, in terms of "possible for our users to do the things they truly need; though not always everything that they want; unless those wants add up to real annoyance".  Eh, that's just me; I bet Bob would explain our feature inclusion criteria much differently.


Lifecycles
==========
I didn't see any particular lifecycle stuff, maybe I missed it. Pretty
much every other IoC container I've used had the concept of pre and
post lifecycle methods / annotations. e.g. in EJB3 its @PostConstruct
and @PreDestroy (which I always get confused about, would have
preferred @Start and @Stop :).  In Spring its an interface
InitializingBean and DisposableBean. These are very common ways to add
a hook that after the Injection has occurred, call a method to
validate the bean is fine and start things off. e.g. its quite common
to have optional injection points but which some combination of
optional properties/fields have to be configured just so for a valid
configuration. So the start hook is just a way of giving the POJO
developer a chance to validate itself.

I've said this elsewhere, but with my limited experience I am still clinging to the romantic notion (ha) that objects should be able to manage to not finish constructing themselves until they're actually ready.  I'm sure there are these dynamite examples that will illustrate to me why that's overly simplistic, I just haven't sought those out yet -- if you can help that'll be fab.

On the opposite side, I do know that objects which hold resources do need an ability to get released; the JDK concept for this is the Closeable interface so the first question on my mind is whether that is the interface guice should recognize.


Avoiding The Hard Guice JAR Dependency
==================================
One idea is for a library like Guice to be able to work with external
annotations to avoid the rather unfortunate jar-dependency issue of
Java annotations.

I've just filed issue 70 to address this jar-dependency issue.
 

e.g. It'd be really cool if out of the box Guice mapped EJB3's
@Resource to @Inject(optional=false) and ditto for Spring & SCA
annotations etc

Not sure about out of the box... but the issues mentioned above would allow you to have this.

Again, your feedback is extraordinarily detailed and astute.  More!

K

Kevin Bourrillion

unread,
Mar 15, 2007, 3:59:34 PM3/15/07
to google...@googlegroups.com
On 3/15/07, Ben <ajoo....@gmail.com> wrote:

Yes. I understand that. But I never feel comfortable with this feature
of Spring.

It might cause surprises. Suppose I have a class and it is injected by
Guice. Everything works fine until some developer adds another
constructor. This change itself looks quite innocent. Common sense
tells me that adding a new method/ctor will not break existing code
(at least when the compiler does not complain).

Personally I feel more comfortable without such intelligence built-in
the container. I'd rather to use annotation to disambiguate
explicitly.

Yes, practically it might has its convenience side. But simply adding
a @Inject annotation is quite convenient already.


Very well put, and this is exactly the kind of risk that I hope we evaluate carefully for every change.  By using guice we should not be transforming someone's world into a mysterious place where innocuous things they do can have unforeseen side-effects!

By the way, that reminds me -- all the information about Spring and Pico and Nano and how they handle similar situations is all very helpful!  But I have one caveat.  In my opinion, personally, I'm more interested in reaching out to the non-DI-infected crowd.  If their app is complex, they're probably living in a hell they don't even realize doesn't have to be that way.  I think most about how we can help *their* transition from the static jail cell they're incarcerated in, into the wonderful rolling fields and wide-open skies of Guice and Spring and friends.  Hmmm.  Let's stop a moment, and hold hands and sing.

No wait, what I mean is, I just want to safeguard Guice's low barrier to entry (= Java 5) and lower it further (see some recently filed issues).  And if people are happy using Spring and aren't inclined to switch, I don't think that bothers me.

Bob on the other hand?...... :-)

K

Hani Suleiman

unread,
Mar 15, 2007, 4:04:18 PM3/15/07
to google...@googlegroups.com
On Mar 15, 2007, at 3:59 PM, Kevin Bourrillion wrote:

>
> No wait, what I mean is, I just want to safeguard Guice's low
> barrier to entry (= Java 5) and lower it further (see some recently
> filed issues). And if people are happy using Spring and aren't
> inclined to switch, I don't think that bothers me.
>

Sure, the issue isn't existing spring users specifically though, it's
people who have to wire up any third party components (whether spring
beans or something else) quickly and easily without writing custom code.

Kevin Bourrillion

unread,
Mar 15, 2007, 5:13:45 PM3/15/07
to google...@googlegroups.com
Consider my little ramble to just be a random off-topic aside.

K

Bob Lee

unread,
Mar 15, 2007, 7:43:43 PM3/15/07
to google...@googlegroups.com
Thanks for the great feedback, James. Kevin covered most of it, so I'll try to keep it short.

The current behavior of @Inject is very deliberate (we do allow no-arg constructors sans @Inject though).

Working on AdWords, we spent a lot of time in other people's code. I care about being concise, but I care more about the next developer who comes along and maintains my code. @Inject makes it very clear to them exactly what is injected (let alone that something funny is going on at all). I also don't want Guice calling random setter methods when I don't expect it. You shouldn't have to resort to a debugger to figure out what's going on in my code.

I like your suggestion for decoupling code from @Inject with a surrogate annotation, but I think we should just wait until we standardize this stuff instead (and I think JSR 299 is the venue for that). We could decouple @Inject now, but that still leaves binding annotations, scopes, providers, etc. @Inject is just the most obvious dependency.

Regarding lifecycle, you can do most of the initialization in a constructor and the remaining optional part in a method. For example:

  @Inject(optional=true)
  void injectOptionalDependencies(...) {
     // validate here.
     ...
  }

I'm not sure Guice should handle the "stop" lifecycle event directly. You can rely on garbage collection for most things. I suppose we could hook this into scopes, but I haven't come across many compelling use cases.

Now, if you want to help Guice users use ActiveMQ without creating a dependency from ActiveMQ on Guice, you could offer a separate Guice integration package. The package could include an ActiveMqModule which would create bindings for ActiveMQ services. You could also provide custom providers (with static factory methods) which users could use to create their own custom bindings to ActiveMQ services.

Thanks,
Bob

On 3/15/07, James Strachan <james.s...@gmail.com> wrote:

James Strachan

unread,
Mar 16, 2007, 5:10:20 AM3/16/07
to google...@googlegroups.com
On 3/15/07, Bob Lee <craz...@crazybob.org> wrote:
> Thanks for the great feedback, James. Kevin covered most of it, so I'll try
> to keep it short.
>
> The current behavior of @Inject is very deliberate (we do allow no-arg
> constructors sans @Inject though).
>
> Working on AdWords, we spent a lot of time in other people's code.

Which BTW you could change, all the source code is in your SCM repo
:). Its quite different when working with a ton of jars made by others
- then keeping that separate boilerplate code in sync with some other
project's releases.


> I care
> about being concise, but I care more about the next developer who comes
> along and maintains my code. @Inject makes it very clear to them exactly
> what is injected (let alone that something funny is going on at all). I also
> don't want Guice calling random setter methods when I don't expect it. You
> shouldn't have to resort to a debugger to figure out what's going on in my
> code.
>
> I like your suggestion for decoupling code from @Inject with a surrogate
> annotation, but I think we should just wait until we standardize this stuff
> instead (and I think JSR 299 is the venue for that).

We've already got Guice annotations and in common use today we've got
JSR 250/EJB3 annotations, SCA standard annotations, Spring annotations
and others (using in HiveMind & Stripes off the top of my head) then
JSR 299 coming down the pipe too. So we've plenty of standards already
(3 actual standards and one common use-standard). I don't see one
clear winner coming along any time soon; so a little bit of
flexibility in this area is already sounding like a good thing


> We could decouple
> @Inject now, but that still leaves binding annotations, scopes, providers,
> etc.
> @Inject is just the most obvious dependency.

Its the most pervasive dependency and is a requirement for anyone to
write a POJO which guice can inject without any extra boilerplate
code. I don't mind having a small number of guice specific classes
inside each library I work on which deal nicely with
modules/providers/scopes but there's no way I'm gonna litter the
entire codebase with an annotation from Guice, unless I happen to be
building an in-house web app or something :)

To me not allowing @Inject to be decoupled is a pretty major barrier
to adoption for library developers; I see myself and other library
developers just not bothering with nice Guice integration as its
either an extra jar dependency (for 1 trivial annotation!) or too much
unnecessary boilerplate code (again to avoid 1 annotation).

Whereas I think it'd be trivial for us all to just add a few
annotations for injection points and write 1 little *optional* class
used when folks actually do use Guice to bind these annotations nicely
into Guice. (Ditto we could bind these annotations to Spring or JBoss
too).

I really don't see the big deal in writing a little strategy
responsible for finding the injection constructor or finding the
injection methods/fields & allowing the annotations used to mark those
injection points as being configurable by library developers.

I'd even love to be able to use the guice DSL to find those injection
points. e.g.

// lets bind in EJB3 injection points in my module...
binder.mandatoryInject(myMatcher).annotatedBy(Resource.class)


> Regarding lifecycle, you can do most of the initialization in a constructor
> and the remaining optional part in a method. For example:
>
> @Inject(optional=true)
> void injectOptionalDependencies(...) {
> // validate here.
> ...
> }

Firstly this does not work with field or setter injection. Also how
can you do that if I have 3 optional dependencies which may or may not
be injected in some class? Must I have 1 method that injects every
possible optional property in one go, then use null values to detect
if specific properties are are not really being passed in? Or maybe
create a method for every permutation of those 3 optional properties.
Then if there are multiple optional methods, how does the POJO know
which one was called last? When the number of properties gets above 10
things get very strange - and there's the issue of default values and
optionally configurable primitive types to worry about too.

One of the main aims of IoC has always been for the POJO developer to
not worry about what the injection is or how the injector works - just
to decide what injection points are possible (where it could take
place) and a way to validate that the object is valid after injection.
Given that there can be multiple injection points; there is a common
need to be notified when injection has completed so you can validate.
Forcing the POJO developer to write yet more boilerplate methods to
inject every different permutation of optional parameters that the
injector/assembler may decide to specify seems a bit unnecessary. I'm
surprised I'm saying this but for once EJB actually has a more elegant
solution in @PostConstruct :).

I *love* constructor injection; which works great for mandatory
injections; it just doesn't deal with optional injection/configuration
with default values at all. As soon as components have optional
injection points, there really is a big need in non-trivial POJOs for
a single post-construction hook as used in every other IoC framework
I've seen (EJB3, Spring, Pico, HiveMind etc).


> I'm not sure Guice should handle the "stop" lifecycle event directly. You
> can rely on garbage collection for most things. I suppose we could hook this
> into scopes, but I haven't come across many compelling use cases.

Connection pooling is the common case, particularly when using
request-scope stuff; inject a Connection then close it when the scope
is closed. So its not so much when garbage collection kicks in, its
usually when a scope is closed. Another common use case of this is
when using singletons within an application scope which includes your
various connections and so forth; then when the application terminates
(e.g. your web app is undeployed) you get a nice point in which to
close things as part of the container lifecycle (rather than relying
on GC which is a bad way to deal with network connections etc).

To be honest the "stop" lifecycle is much rarer; though the "start"
lifecycle is very common.


> Now, if you want to help Guice users use ActiveMQ without creating a
> dependency from ActiveMQ on Guice, you could offer a separate Guice
> integration package. The package could include an ActiveMqModule which would
> create bindings for ActiveMQ services. You could also provide custom
> providers (with static factory methods) which users could use to create
> their own custom bindings to ActiveMQ services.

I understand that its possible to write reams of derived classes /
providers / factory methods to allow stuff to be Guice-capable. I'm
just trying to explore a simpler approach for us POJO developers who
want to work with IoC containers like Guice and Spring; but want to
avoid writing reams of unnecessary code.

e.g. I'd like to have zero mandatory dependencies on Spring or Guice
in, say, ActiveMQ, just a few internal inject & lifecycle annotations;
then have a simple generic binding from my annotations to Guice &
Spring - rather than have to bind 100 or so POJOs individually to both
Spring and Guice.

Its pretty trivial in Spring for example to add a policy to use my own
injection & lifecycle annotations; the main reason folks don't do this
is it'd mean a little more XML required in each XML file, which folks
might forget to include - so its typically easier to just use the
Spring annotations/interfaces. However if the XML is ditched and Java
code is used instead, its very trivial to decouple those
injection/lifecycle annotation points.

I understand the reluctance to add features for fear of bloat or
adding things which could harm the common use cases. Though I still
think there should be a little flexibility in this area as we're only
talking about a couple of fairly trivial optional plugin strategies
(which 'good' users of guice probably wouldn't use or even see) which
IMHO would really help in Guice adoption. e.g. adding a plugin to
automatically inject any Spring or EJB3 POJO without any extra
boilerplate code would be extremely useful & really help folks migrate
from spring/ejb3 to guice.

I love that the out of the box guice encourages good use of explicit
@Inject annotations; I'd just like a way to reuse code which is either
legacy, cannot use Guice annotations or uses another standard form of
annotations already (EJB3/JSR250, SCA, Spring, JBoss or others) which
could be trivially mapped to Guice with a minimum of fuss.

Bob Lee

unread,
Mar 16, 2007, 2:13:32 PM3/16/07
to google...@googlegroups.com
I think provider interceptors can address all of your concerns (I mentioned them here http://code.google.com/p/google-guice/issues/detail?id=62&can=2&q=lifecycle ).

Provider interceptors could be chained. They would run after injection but before scoping. You could apply them orthogonally to bindings (i.e. you could apply a provider interceptor to all bindings to classes in the ActiveMQ package).

You could implement a provider interceptor which could do any of the following:

1) Call init() after injection.
2) Call methods annotated with @PostConstruct.
3) Inject methods annotated with @Resource.
4) Auto-wire beans (i.e. call setters).

Bob

Kevin Bourrillion

unread,
Mar 18, 2007, 3:48:58 AM3/18/07
to google...@googlegroups.com
On 3/15/07, Bob Lee <craz...@crazybob.org> wrote:

I like your suggestion for decoupling code from @Inject with a surrogate annotation, but I think we should just wait until we standardize this stuff instead (and I think JSR 299 is the venue for that). We could decouple @Inject now, but that still leaves binding annotations, scopes, providers, etc. @Inject is just the most obvious dependency.

"Wait instead"?  <barf> 

Binding annotations - remind me what breaks if we were to stop requiring that binding annotations be annotated?
Scopes - people can just scope in their Module, not on their impl class.
Providers - people can also adapt their "pure" impl code to our Provder interface in their Module.

I still think there's value in letting the user specify the annotations they wish Guice to recognize as marking injection points.


I'm not sure Guice should handle the "stop" lifecycle event directly. You can rely on garbage collection for most things. I suppose we could hook this into scopes, but I haven't come across many compelling use cases.

Suppose I have an object which holds open certain resources while it is alive.  It periodically falls out of scope and is replaced by a new instance in a new scope.  It would be Very Bad if the new object was born and started consuming the resources before the old object had the chance to properly release them.

If my object implements Closeable -- or otherwise exports some information that tells frameworks how to close it -- then I think I'd be a little bummed if my object's scope didn't bother to tell me when it was done with me.

In a case like this, the idea of "relying on garbage collection" really makes me queasy.  What do you think, Bob?

K

Ben

unread,
Mar 18, 2007, 9:05:46 AM3/18/07
to google...@googlegroups.com
I don't think we should rely on gc. Should we decide that Closeable is
a valid use case, it's better be called by the container.

Maybe, the Provider interface should have a "release(T)" method to
handle the releasing?

Bob Lee

unread,
Mar 18, 2007, 9:40:53 PM3/18/07
to google...@googlegroups.com
On 3/18/07, Kevin Bourrillion <kevi...@gmail.com> wrote:
Binding annotations - remind me what breaks if we were to stop requiring that binding annotations be annotated?

@BindingAnnotation makes it clear which annotations are used for binding. We give a clear error if you use more than one binding annotation on the same injection point. If we didn't have @BindingAnnotation, we would have to iterate over every annotation at an injection point and lookup up a binding for each. Right now, if the user applies a binding annotation to an injection point but forgets to create a binding to it, they get an error. If we didn't have @BindingAnnotation, Guice would probably silently pick the default binding to that type instead. Sure, the user could still forget to apply @BindingAnnotation and forget to bind something to it, but I suspect it's more common to do one or the other, in which case they get a clear error.

Providers - people can also adapt their "pure" impl code to our Provder interface in their Module.

I'm talking about injecting providers into your code.

I still think there's value in letting the user specify the annotations they wish Guice to recognize as marking injection points.

I don't think it carries its weight.

I said earlier that projects like ActiveMQ could provide separate Guice integration packages to users. I'm not sure if anyone responded to this idea. I think James might have complained about "boilerplate," but isn't this analogous to the Spring XML boilerplate all your users would have to write? At least with a Guice integration package, it's a one time effort and you can keep the package in sync with your project.

I'm not sure Guice should handle the "stop" lifecycle event directly. You can rely on garbage collection for most things. I suppose we could hook this into scopes, but I haven't come across many compelling use cases.

Suppose I have an object which holds open certain resources while it is alive.  It periodically falls out of scope and is replaced by a new instance in a new scope.  It would be Very Bad if the new object was born and started consuming the resources before the old object had the chance to properly release them.

If my object implements Closeable -- or otherwise exports some information that tells frameworks how to close it -- then I think I'd be a little bummed if my object's scope didn't bother to tell me when it was done with me.

In a case like this, the idea of "relying on garbage collection" really makes me queasy.  What do you think, Bob?

I'm not saying real use cases don't exist, but we still don't have any. Someone mentioned database connections, but when's the last time you dealt directly with a database connection? When it comes to heavy resources for which you can't rely on garbage collection (database connections, sockets, files), I make sure to open and close these in close proximity, and in a finally block.

Bob

Dhanji R. Prasanna

unread,
Mar 18, 2007, 9:51:29 PM3/18/07
to google...@googlegroups.com
On 3/19/07, Bob Lee <craz...@crazybob.org> wrote:
On 3/18/07, Kevin Bourrillion <kevi...@gmail.com> wrote:
Binding annotations - remind me what breaks if we were to stop requiring that binding annotations be annotated?
 @BindingAnnotation and forget to bind something to it, but I suspect it's more common to do one or the other, in which case they get a clear error.

I agree, principle of least surprise, those annotations are used only for binding so it's fair to require them to be annotated themselves. The idea of adapting pre-existing annotations (@Resource, etc.) can be done with Bob's post-processing provider dealy.


In a case like this, the idea of "relying on garbage collection" really makes me queasy.  What do you think, Bob?

I'm not saying real use cases don't exist, but we still don't have any. Someone mentioned database connections, but when's the last time you dealt directly with a database connection?

Yea but conversely you deal with abstract persistence "sessions" and/or txns all the time. If sessions are long-lived (in hibernate/JPA for instance), a stop lifecycle-event is a real requirement.

Im not really behind this one, just highlighting a common use case. Perhaps it could be an optional module (using a "well-known" aspect such as Closeable to fire stop events)?

With the chained injectors coming in 2.0 I think there is a requirement for "stopping" child injectors (and their objects) that may be holding on to a parent's resources. Still sounding vague, I know =(

Bob Lee

unread,
Mar 18, 2007, 10:11:35 PM3/18/07
to google...@googlegroups.com
On 3/18/07, Dhanji R. Prasanna <dha...@gmail.com> wrote:
I'm not saying real use cases don't exist, but we still don't have any. Someone mentioned database connections, but when's the last time you dealt directly with a database connection?

Yea but conversely you deal with abstract persistence "sessions" and/or txns all the time. If sessions are long-lived (in hibernate/JPA for instance), a stop lifecycle-event is a real requirement.

Can you go into more detail?

Bob

Dhanji R. Prasanna

unread,
Mar 18, 2007, 10:22:48 PM3/18/07
to google...@googlegroups.com
On 3/19/07, Bob Lee <craz...@crazybob.org> wrote:

You have a PersistenceManager to wrap Hibernate Sessions. At the beginning of a user conversation you open the session. Then do plenty of work with the session in various objects (across many txns). The entities bound to the session are not in the db yet (dirty state management).

Some event triggers (typically not driven by lexical structure of code) a conversation end, the PersistenceManager must now close the session to flush dirty data to the db. The PersistenceManager is disposed.

The more common pattern is to have a short lived session around a single http request (if in a webapp), this is somewhat less of a viable use case for stop-lifecycle because requests can be wrapped with around advise.

Bob



Bob Lee

unread,
Mar 18, 2007, 10:30:20 PM3/18/07
to google...@googlegroups.com
On 3/18/07, Dhanji R. Prasanna <dha...@gmail.com> wrote:
You have a PersistenceManager to wrap Hibernate Sessions. At the beginning of a user conversation you open the session. Then do plenty of work with the session in various objects (across many txns). The entities bound to the session are not in the db yet (dirty state management).

Some event triggers (typically not driven by lexical structure of code) a conversation end, the PersistenceManager must now close the session to flush dirty data to the db. The PersistenceManager is disposed.

What would stop() mean here? You say you would flush the dirty data to the database, but what if the user abandoned the conversation in which case you should just throw the data away? I prefer to make an explicit commit() call from my code at the successful end of a conversation.

Bob

Dhanji R. Prasanna

unread,
Mar 18, 2007, 10:44:05 PM3/18/07
to google...@googlegroups.com
On 3/19/07, Bob Lee <craz...@crazybob.org> wrote:

you're referring to a transaction commit. I am referring to a session flush, as far as the persistence mechanism is concerned the transactions have already succeeded/failed, its just the dirty state which hasnt been sync'ed to the db (and of course the JDBC connection released to the pool, held references released to the gc etc.).

Think more along the lines of delayed write caching (but more than that).

Again Im iffy on the role of guice here, just playing devil's advocate (though devil/kevin may have a point here =).

Bob




Bob Lee

unread,
Mar 18, 2007, 11:40:49 PM3/18/07
to google...@googlegroups.com
On 3/18/07, Dhanji R. Prasanna <dha...@gmail.com> wrote:
you're referring to a transaction commit. I am referring to a session flush, as far as the persistence mechanism is concerned the transactions have already succeeded/failed, its just the dirty state which hasnt been sync'ed to the db (and of course the JDBC connection released to the pool, held references released to the gc etc.).

Assuming a conversation spans multiple requests, you shouldn't hold onto a database connection across requests--it doesn't scale. I also think the data should be flushed as part of the transaction; otherwise, what's the point of the transaction?

Bob


Dhanji R. Prasanna

unread,
Mar 19, 2007, 12:56:35 AM3/19/07
to google...@googlegroups.com
On 3/19/07, Bob Lee <craz...@crazybob.org> wrote:
On 3/18/07, Dhanji R. Prasanna <dha...@gmail.com> wrote:


Assuming a conversation spans multiple requests, you shouldn't hold onto a database connection across requests--it doesn't scale. I also think the data should be flushed as part of the transaction; otherwise, what's the point of the transaction?

This is only true for webapps and even then not really as persistence tools like hibernate will temporarily disconnect connections during user-think time. I really dont think you can say long lived sessions are a red herring. It is a legitimate use case, even in webapps:

http://www.hibernate.org/42.html (see session-per-conversation strategy)

more devil advocacy: one can find all kinds of use cases for stop when you look at containers--SWT widgets need to dispose themselves, rmi services need to be closed, custom network layers or ftp clients need to send a death signal, caches need to dispose of disk resources, etc.

Anyway, that's about the most arguing I am willing to do for this point. As Ive said all along Im not in favor of ANY lifecycle support in guice (the upcoming postprocessor can register methods marked with @PreDestroy to a shutdown registry; and theres nothing wrong with using constructor/method injection for init...).

Bob





Reply all
Reply to author
Forward
0 new messages