views:

1084

answers:

3

Hi,

We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. We have added Spring recently, and we would like to autowire our beans in our modified JSP, while not rewriting everything to use SpringMVC, Struts2 or Tapestry5.

We're using autowiring by type, so it leads to get some code like this in the JSP, while previously getting the web application context ( as "wap") :

MyDao myDao = (MyDao) wap.getBeansOfType(MyDao.class).values().toArray()[0];

We would like not to use such a code but rather automagically inject our beans directly in our JSPs as we would in a business bean using @Autowired annotation.

In fact we're looking to the cleanest ways to inject our beans in our JSPs. What do you use ?

+5  A: 

You can use Spring's ContextExposingHttpServletRequest:

HttpServletRequest decorator that makes all Spring beans in a given WebApplicationContext accessible as request attributes, through lazy checking once an attribute gets accessed.

This would require your controller code to wrap the original HttpServletRequest in a ContextExposingHttpServletRequest, and then forward that to the JSP. It can either expose specific named beans, or every bean in the context.

Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem.

skaffman
What do you think about changing this to a filter (rather than a servlet) on top of JSPs which get all beans from Spring context and put them in the request scope, named by the expected interface in order to have a simili getByType ?
temsa
Good idea, should work
skaffman
(+1) Nice catch with the request-wrapper.still, `@Autowired` won't be usable that way?
Bozho
@Bozho: it won't, no, but the beans can just be referred to in the JSP, without any explicit wiring for it.
skaffman
We probably can use http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/filter/DelegatingFilterProxy.html as a base for the filter
temsa
A: 

You can't use @Autowired directly because both your jsps and servlets are instantiated by the servlet conainer. So they are not part of the spring context and hence their dependencies aren't injected.

You can:

  1. move all code that to pure servlets, rather than in jsps - leave only presentation in the jsps.
  2. use @Configurable on your servlets (and add a javaagent, as described in the linked docs)

Another way, is to make the servlet part of the current context manually. This is possible in both jsps and servlets:

public void init() {
    WebApplicationContext ctx = WebApplicationContextUtils
         .getRequiredWebApplicationContext(getServletContext());

    AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();

    bf.autowireBean(this);
}

This will resolve the @Autowired annotated dependencies.

Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. If not, you'd better place the above code in a getter-method for the dependency (getDao()) and if the @Autowired property is null (i.e. another instance of the servlet-class is used by the container) - perform the above operation.


That all said, really consider using a web framework (any of the ones you listed). Having logic in jsps is completely wrong, hard to support, hard to read, etc.

Bozho
I definitively know, but you can't rewrite a whole software in 5 days(including splitting front and business logic), while adding new features. In fact we should avoid using the DAO there and write then rely only on the business object too, but this is just some already written code that I can't rewrite in such a few time.Convincing managers to convert the app to Spring/Hibernate/Jpa instead of home made singletons and company made ORM tools was already a great pain. They only see that as a cost...
temsa
+3  A: 

I doubt that there is a clean way to inject dependencies into a JSP.

I think that the clean solution would be to start refactoring your code to get the business logic out of the JSPs, using either SpringMVC or one of the alternatives you cited.

Start with one or more minimalist controllers that simply pass the request to the JSPs with the injected beans as attributes; @skaffman's answer gives one way to do that, or you could do it more selectively. Then progressively migrate code out of the JSPs and into the controllers.

Stephen C