Question

I am using Spring framework (2.5.4) in my app with Load time weaving and everything works fine everywhere (in Spring beans, in non-Spring entities), except when I try to autowire field in a servlet annotated as @Configurable, then I get a nice NullPointerException...


@Configurable(dependencyCheck=true)
public class CaptchaServlet extends HttpServlet{
    @Autowired
    private CaptchaServiceIface captchaService;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    //    ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
    //    captchaService = (CaptchaServiceIface) ctx.getBean("captchaService");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Captcha c = captchaService.getCatpcha();
        req.getSession().setAttribute("captchaAnswer", c.getAnswer());
        resp.setContentType("image/png");
        ImageIO.write(c.getImage(), "png", resp.getOutputStream());
    }
}

<context:load-time-weaver/>
<context:spring-configured/>
<context:component-scan base-package="cz.flexibla2" />

Any suggestions about what am I doing incorrectly?

Thanks.

Was it helpful?

Solution

See also mailing list discussion and bug report at https:// bugs.eclipse.org/bugs/show_bug.cgi?id=317874 . I agree that intuitively the @Configurable annotation on the servlet should be enough to indicate to the spring framework that the servlet when instantiated will be configured by spring, when using <context:spring-configured/>. I have also observed that the desired behavior is achievable when using the -javaagent:/path/to/aspectjweaver.jar instead of spring-instrument*.jar or spring-agent.jar. Please raise an issue with Spring Jira at https:// jira.springframework.org/browse/SPR. I believe that the problem may be that the servlet class - not an instance of the servlet, but the class itself - is loaded before the spring ContextLoaderListener is called, thus the spring framework does not have a chance to instrument the servlet class before it is loaded.

The spring instrumentation for load-time-weaving appears to be based on being able to transform class bytecode before it is loaded. If the servlet container is holding onto an instance of the Class object that was obtained before it was transformed by spring, then it (the servlet container) would not be able to produce instances of the transformed class, nor would spring be able to instrument instances created using the factory methods on that Class object.

OTHER TIPS

This is likely because the Servlet is being instantiated and initialized by the servlet container, before the Spring context is being initialized, and it's the Spring context which handles the load-time weaving.

Is your <context:load-time-weaver/> stuff being handle inside the servlet Spring context/ or at the webapp-level? The former almost certainly won't work (for the reasons specified above), but a webapp-level config might work (using ContextLoaderListener).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top