javaspringspring-bootweb.xmlspring-java-config

Spring Boot take over web.xml configuration


I have a Spring Boot web application that works fine. Now I got a 3rd party lib which I must use in the project. The manual of integrating the lib is written with respect to an existing web.xml file. My project completely relies on a Java based config.

According to the Spring documentation I can reach my goal of taking over the web.xml content into my application with the help of a WebApplicationInitializer.

That's what I did (at least I think I did it correctly). Before going into more details, here is the web.xml:

<servlet>
   <servlet-name>LoginServlet</servlet-name>
   <servlet-class>some.package.path.LoginServlet</servlet-class>
</servlet>
<servlet>
   <servlet-name>LogoutServlet</servlet-name>
   <servlet-class>some.package.path.LogoutServlet</servlet-class>
</servlet>
<servlet>
   <servlet-name>ResultServlet</servlet-name>
   <servlet-class>some.package.path.ResultServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>LoginServlet</servlet-name>
   <url-pattern>/saml/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
   <servlet-name>LogoutServlet</servlet-name>
   <url-pattern>/saml/logout</url-pattern>
</servlet-mapping>
<servlet-mapping>
   <servlet-name>ResultServlet</servlet-name>
   <url-pattern>/saml/result</url-pattern>
</servlet-mapping>
<env-entry>
   <env-entry-name>some.package.path.config-file</env-entry-name>
   <env-entry-type>java.lang.String</env-entry-type>
   <env-entry-value>$HOME/.libName/libName-config.xml</env-entry-value>
</env-entry>

And here is how I refactored this in a Java config:

public class WebAppInitializer implements WebApplicationInitializer {

    private static final Logger LOG = Logger.getLogger(WebAppInitializer.class.getSimpleName());

    @Override
    public void onStartup(ServletContext servletContext) {
        final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.scan("de.davidartmann.myapp.configuration");

        final ServletRegistration.Dynamic dispatcher =
            servletContext.addServlet("dispatcher", new DispatcherServlet(context));

        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        final ServletRegistration.Dynamic loginServlet =
            servletContext.addServlet("LoginServlet", LoginServlet.class);
        loginServlet.addMapping("/saml/login");

        final ServletRegistration.Dynamic logoutServlet =
            servletContext.addServlet("LogoutServlet", LogoutServlet.class);
        logoutServlet.addMapping("/saml/logout");

        final ServletRegistration.Dynamic resultServlet =
            servletContext.addServlet("ResultServlet", ResultServlet.class);
        resultServlet.addMapping("/saml/result");

        try {
            final InitialContext initialContext = new InitialContext();
            initialContext.addToEnvironment("some.package.path.config-file",
                "$HOME/.libName/libName-config.xml");
        } catch (NamingException e) {
            LOG.log(Level.SEVERE, "Could not initialize an InitialContext", e);
        }
    }
}

The problem is that the 3rd party lib throws an internal NPE with this setup. The NPE is thrown at the point where it @Injects (based on CDI) the runtime object of the <env-entry> in the web.xml which I implemented as InitialContext in my WebAppInitializer class.

My Spring Boot application uses a SpringBootServletInitializer. The Spring documentation about Traditional Deployment mentions it with the words:

Normally, all the code from an existing WebApplicationInitializer can be moved into a SpringBootServletInitializer

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(MyApplication.class);
    }
}

Now, I am a unsure what to do? Is my implementation of WebApplicationInitializer correct or do I need to use the SpringBootServletInitializer in my Spring Boot main class?

Thanks for your help. David


Solution

  • The problem was, that the Tomcat server which was used to deploy the application does not provide an implementation for the dependency injection (CDI). I had to change to Wildfly which provides the necessary implementation.