My app is pretty much straight Java, no EJBs or anything like that,
running inside an application server. This means there are multiple
entry points: 1) the class I specify that has its
contextInitialized(ServletContextEvent) method called on startup, and
2) the classes that handle HTTP requests.
I currently have this in contextInitialized():
this.injector = Guice.createInjector(new Bindings(dataSource,
this));
where Bindings is obviously a Module that sets up instance and class
bindings.
However, none of the servlet request handling instances are created by
me (or Guice), but by the application container. Therefore, they don't
get their fields injected into, therefore I get NullPointerExceptions
coming up.
What's the recommended method of combining Guice with servlets like
this? The only way I can see is for them to request an injector from
somewhere static, and use that, but that seems to be defeating the
whole purpose, so I'm sure there's a better way.
Thanks, Robin.
So, you'd have to go with a base class. Something like this:
public abstract class AbstractInjectableServlet
public void init(ServletConfig config)
{
//look up injector from config.getServletContext()
injector.injectMembers(this);
}
That way all the subclasses will get injected at construction time.
If you want to bypass the servlet specification, you can override the
code in Jetty that creates new Filters, Listeners and Servlets and
replace it with something that does injection.
So, its possibly, just non-portable. Works great if you're using
Jetty anyways though.
-pete
--
(peter.royal|osi)@pobox.com - http://fotap.org/~osi
Cheers, Robin.
But when it comes to how exactly someone would make use of this, I'm fuzzy. I think they could extend it with a class like this:
> Now I'm trying to figure out what to fill in for "foo koo joo
> boo". My servlet understanding is weak since we don't tend to do
> much with them directly here. I've figured, maybe something like
> this?
>
> public class GuiceServletContextListener implements
> ServletContextListener {
> private final Injector injector;
>
> @Inject public GuiceServletContextListener(Injector injector) {
> this.injector = injector;
> }
No, the context listener creates the injector, it isn't a target of
injection itself.
> And then I think they have some way of registering this class as a
> servlet context listener, but I suspect that the way they do this
> registration may possibly not be standardized between all servlet
> engine implementations, because I can find no method in
> javax.servlet that actually takes in one of these things. But
> again, I'm out of my comfort zone here, so I hope y'all can set me
> straight about this fancy servlet stuff. Thanks!
>
It's done in web.xml, via a <listener> element, and it's part of the
spec.
This is my listener for a generic guice context loader (aka spring's ContextLoaderListener) that I just got done writing
It requires you to specify some config info in web.xml using <context-param> tags.
On Mar 14, 2007, at 12:28 AM, Kevin Bourrillion wrote:
> Now I'm trying to figure out what to fill in for "foo koo joo
> boo". My servlet understanding is weak since we don't tend to do
> much with them directly here. I've figured, maybe something like
> this?
>
> public class GuiceServletContextListener implements
> ServletContextListener {
> private final Injector injector;
>
> @Inject public GuiceServletContextListener(Injector injector) {
> this.injector = injector;
> }
No, the context listener creates the injector, it isn't a target of
injection itself.
> And then I think they have some way of registering this class as a
> servlet context listener, but I suspect that the way they do this
> registration may possibly not be standardized between all servlet
> engine implementations, because I can find no method in
> javax.servlet that actually takes in one of these things. But
> again, I'm out of my comfort zone here, so I hope y'all can set me
> straight about this fancy servlet stuff. Thanks!
>
It's done in web.xml , via a <listener> element, and it's part of the
spec.
On Mar 14, 1:18 am, "Kevin Bourrillion" <kevin...@gmail.com> wrote:
>
> Ah. So do you think, "subclass this class we provide you, implement the
> createInjector() method, and list your class as a <listener> in web.xml" is
> a decent instruction for getting people up and running?
>
This seems perfectly reasonable to me. Since in a non-web
application, you're basically creating your Injector in something like
your main() method (or at startup, etc). This would just do the same
thing.
Here's a modification of Dhanji's class to do just that. I just moved
the Injector creation code to an abstract method. You would probably
want to also move the stageParam and guiceVarName code to abstract
methods as well, just to keep the configuration in one place... Of
course, if you want to configure it all in the web.xml file, Dhanji's
approach is more than sufficient.
Marcus
-----
/**
* @author dprasanna
* @author mbreese
*/
public abstract class AbstractGuiceServletContextListener implements
ServletContextListener {
private String guiceVarName;
protected Stage stage = null;
private static final String DEFAULT_GUICE_VAR_NAME =
Injector.class.getName();
public void contextInitialized(ServletContextEvent
servletContextEvent) {
//read config parameters from servlet context and use defaults
as necessary
final ServletContext servletContext =
servletContextEvent.getServletContext();
final String stageParam =
servletContext.getInitParameter("guice-stage");
guiceVarName = (null == servletContext.getInitParameter("guice-
injector-name")) ? DEFAULT_GUICE_VAR_NAME
: servletContext.getInitParameter("guice-injector-
name");
//try to parse a stage config value (if there is one)
if (null != stageParam) {
try {
stage = Stage.valueOf(stageParam);
} catch(IllegalArgumentException e) {
failStartup("Value specified by parameter guice-stage
MUST be one of { DEVELOPMENT, PRODUCTION }, you specified: " +
stageParam);
}
}
Injector injector = null;
injector = createInjector();
if (injector == null) {
failStartup("Could not create injector: createInjector()
returned null");
}
servletContext.setAttribute(guiceVarName, injector);
}
public abstract Injector createInjector(); // protected?
> I figured this would be the normal usage, but I put @Inject there
> anyway because why the heck not? It's no-cost, and some servlet
> engines (probably including ours we use in my company) may have
> programmatic listener registration and might find it easier to
> create the Injector first and pull the listener instance from it.
> Waaait a minute, am I being insane again? Gotta stop that...
>
Well, in terms of why not, I think it's because it's confusing and
doesn't apply in most cases. Most people will wonder 'how on earth
can guice inject into something that's creating the injector?'
If you're a weirdo and DO need that, then you can subclass the
listener and add the annotation yourself.
>
> Ah. So do you think, "subclass this class we provide you,
> implement the createInjector() method, and list your class as a
> <listener> in web.xml" is a decent instruction for getting people
> up and running?
>
Yep, final step would be to stuff the injector into ServletContext,
which you can then access from anywhere (and note that it can be a
singleton since it's horribly threadsafe).
> thanks Hani -- by the way, you've been an awesome and welcome
> presence on the mailing list! Thanks so much for all the help
> answering questions.
>
My pleasure!
> Well, in terms of why not, I think it's because it's confusing and
> doesn't apply in most cases. Most people will wonder 'how on earth
> can guice inject into something that's creating the injector?'
You're absolutely right!
> > Ah. So do you think, "subclass this class we provide you,
> > implement the createInjector() method, and list your class as a
> > <listener> in web.xml" is a decent instruction for getting people
> > up and running?
> >
> Yep, final step would be to stuff the injector into ServletContext,
> which you can then access from anywhere (and note that it can be a
> singleton since it's horribly threadsafe).
"Horribly threadsafe", I like that. But this injector-stuffing to
which you refer -- is exactly what my listener class is doing.
> > thanks Hani -- by the way, you've been an awesome and welcome
> > presence on the mailing list! Thanks so much for all the help
> > answering questions.
>
> My pleasure!
Oh. What a happy coincidence!
K