Question

my problem is that I can't get servletcontext in my bean. I created custom bean "FileRepository" and I need to get ServletContext there. here is the code

package com.pc.webstore.utils;

import java.io.File;
import java.nio.file.Files;

import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletContextAware;
public class FileRepository implements ServletContextAware {

private ServletContext servletContext;

public String saveFile(File file){
    File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
            ...
}

@Override
public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
    }
}

registration in ApplicationContext.xml

 <bean id="fileStorage" class="com.pc.webstore.utils.FileRepository"/>

when saveFile(File file) starts, I recive Nullpointerexception because servletContext == null.

So why servletcontext does not injected? I have ContextLoaderListener registred in web.xml

   <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

I found that there is some scopes. May be problem is there. Tell me briefly about applicationsontext scope or give the link pleas. Thanks for help. I spent a lot of time for this problem.

After some debuging I understood that setServletContexr method of servletcontextaware is actually was called when app starts but when I tried to store file with FileRepository from my controller, it was already anather object with null servletContext field.

Is there a way just to autowier servlet context in my custom bean when i want, like in controller?

Finaly I get servletContext via ServletContextAware. I change the way of creation fileRepository bean. From this

public String create(@Valid Item item, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, FileRepository fileRepository)     {

to this

@Autowired
private FileRepository fileRepository;

@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid Item item, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
Was it helpful?

Solution

ContextLoaderListener loads an ApplicationContext that becomes the global parent context for the application. There is no ServletContext there. ServletContext only exists within (pardon the overloading of terms) the CONTEXT of a SERVLET- for instance, the DispatcherServlet. Every DispatcherServlet (typically you'd only have one) registers a child context that points back to the global parent context registered by the ContextLoaderListener. ApplicationContexts are like classloaders. When the IOC container goes "looking" for a bean, each ApplicationContext can look "up" to its parent to try to find it, but it can't look down. Children can also override bean definitions from their parent context.

Now... it would seem your problem is that your bean is defined in global parent context where there is no ServletContext to be found. (It can't look "down" to its children to find it.)

What you need to do is move the fileStorage bean definition "down" into the ApplicationContext for the DispatcherServlet.

When you define a DispatcherServlet in your web.xml, you usually specify where it can find the files that define its child context. Like so:

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:/web-context/*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Move that bean definition down into the location specified by contextConfigLocation and everything should work as you expect.

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