3

So, this is something of a follow-on of this question. My current code looks something like this:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"base.pkg.name"})
public class MyApp implements ServletContextAware {

    private ThingDAO beanThingDAO = null;

    public MyApp() {
        // Lots of stuff goes here.
        // no reference to servletContext, though
        // beanThing gets initialized, and mostly populated.
    }

    @Bean publicD ThingDAO getBeanThingDAO() { return beanThingDAO; }

    public void setServletContext(ServletContext servletContext) {
        // all references to servletContext go here, including the
        // bit where we call the appropriate setters in beanThingDAO
    {
}

The problem is, it's not working. Specifically, my understanding was that setServletContext was supposed to be called by various forms of Spring Magic at some point during the startup process, but (as revealed by System.out.println()) it never gets called. I'm trying to finish up the first stage of a major bunch of refactoring, and for the moment it is of notable value to me to be able to handle the access to servletContext entirely inside of the @Configuration file. I'm not looking for an answer that will tell me that I should put it in the controllers. I'm looking for an answer that will either tell me how to get it working inside of the @Configuration file, or explain why that won't work, and what I can do about it.

Ben Barden
  • 2,001
  • 2
  • 20
  • 28
  • It should work :/ Does your `getBeanThingDAO` method gets called? If not than maybe this configuration file is not handeld by spring – Krzysztof Majewski May 03 '18 at 19:38
  • @KrzysztofMajewski: Well, the MyApp() constructor gets called, and changing the basePackages on the ComponentScan decorator changes which areas get checked for controllers. The various Autowire variables get populated, and I don't know of any way that they would except for getBeanThingDAO() being called. – Ben Barden May 03 '18 at 20:11

2 Answers2

1

Well, I have an answer. It's not one I'm particularly happy with, so I won't be accepting it, but if someone with my same problem stumbles across this question, I want to at least give them the benefit of my experience.

For some reason, the ServletContextAware automatic call simply doesn't work under those circumstances. It works for pretty much every other component, though. I created a kludge class that looks something like this:

// This class's only purpose is to act as a kludge to in some way get
// around the fact that ServletContextAware doesn't seem to work on MyApp.
// none of the *other* spring boot ways of getting the servlet context into a
// file seem to work either.
@Component
public class ServletContextSetter implements ServletContextAware {

    private MyApp app;

    public ServletContextSetter(MyApp app) {
        this.app = app;
    }

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

Does the job. I don't like it, and I will be rebuilding things later to make it unnecessary so I can take it out, but it does work. I'm going to hold the checkmark, though, in case anyone can tell me either how to make it work entirely inside the @Configuration - decorated file, or why it doesn't work there.

Note that the @Component decorator is important, here. Won't work without it.

Ben Barden
  • 2,001
  • 2
  • 20
  • 28
1

I just ran into a very similar issue and while I'm not positive it's exactly the same problem I thought I'd record my solution in case it's helpful to others.

In my case I had a single @Configuration class for my spring boot application that implemented both ServletContextAware and WebMvcConfigurer.

In the end it turns out that Spring Boot has a bug (or at least undocumented restraint) that ServletContextAware.setServletContext() will never be called if you also implement WebMvcConfigurer on the same class. The solution was simply to split out a separate @Configuration class to implement ServletContextAware.

Here's a simple project I found that demonstrates and explains more what the problem was for me: https://github.com/dvntucker/boot-issue-sample

The OP doesn't show that the bean in question was implementing both of these, but given the OP is using simplified example code I thought maybe the fact that the asker could have been implementing both interfaces in his actual code and might have omitted the second interface.

StormeHawke
  • 5,987
  • 5
  • 45
  • 73