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/
- 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>
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
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.
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:
>
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.
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?
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).
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.
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.
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
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.
>
> 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.
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.
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.
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.
Maybe, the Provider interface should have a "release(T)" method to
handle the releasing?
Binding annotations - remind me what breaks if we were to stop requiring that binding annotations be annotated?
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?
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.
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?
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.
Bob
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.
Bob
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.).
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?
Bob