Nicholas
Nicholas

Reputation: 3336

How to set up Spring so that I can omit applicationContext.xml

I have a JAX application using spring to set up the context.

I have set up an AppConfig to deal with this... like so.

@Configuration
@ComponentScan("com.whatever")
public class AppConfig {... //etc

However, I keep getting an error because the application is looking for the applicationContext.xml.

org.springframework.beans.factory.BeanDefinitionStoreException: 
IOException parsing XML document from class path resource [applicationContext.xml];

I believe I have to do something with my web.xml file... but I can't quite figure it out. Here's my web.xml

<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">

<listener>
    <listener-class>com.whatever.etc.ApplicationListener</listener-class>
</listener>

<!-- Application -->
<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
            io.swagger.jaxrs.listing,
            com.shutterstock.media.api
        </param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.provider.scanning.recursive</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.whatever.etc.MainClass</param-value>
    </init-param>
    <init-param>
        <param-name>dirAllowed</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <!-- used to overwrite default 4xx state pages -->
        <param-name>jersey.config.server.response.setStatusOverSendError</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

<servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<!-- Swagger -->
<servlet>
    <servlet-name>Jersey Swagger</servlet-name>
    <servlet-class>io.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

</web-app>

Upvotes: 1

Views: 3435

Answers (2)

Tom
Tom

Reputation: 3850

The best advice I can give you is fully transform your project to spring boot in order to take advantage of all the great functionality it offers.

You should completely remove all XML from your project and do the following steps:

TL;DR

An easy way to start with spring boot is using spring initializr (Spring initializr) and start migrating your code to the new project.

Explanations of starting steps to migrate to spring boot in an existing project:

Maven Dependencies

Add the following dependencies and remove all other related spring dependencies. In general if you need any other dependency try to first check if there is a spring boot starter for it. (also make sure your packaging is jar. if you want a war you should follow this link: convert to war)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Spring Boot Application

Create a class annotated with @SpringBootApplication that looks like the following in your base package. From this point on create classes only in sub-packages of this package so spring can catch all of your components automatically:

@SpringBootApplication
public class FooApplication {

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

}

Java Configuration

now you can easily add a package called config for example under your base package and add @Configuration annotated beans with your custom configuration.

application.properites/yml

If you don't already have, add application.properties/yml to src/main.resources with the following configuration as a minimum (more properties can be found here: spring boot common properties)

  • Map jersey servlet endpoint by adding: spring.jersey.application-path=/

Jersey Configuration

You need to register jersey providers in a custom java configuration class that extends ResourceConfig:

@Configuration
public class JerseyConfiguration extends ResourceConfig {

    public JerseyConfiguration() {
        register(FooController.class);
        register(OtherController.class);
        ...
    }

}

Important Notes

After doing this transformation you don't need web.xml anymore as spring boot takes care of creating servlets for you. You should remove all XML from your project except for the pom.xml and convert everything to java. It can coexist with your XML configuration using @ImportResource but it is not recommended.

In order to run your project now with maven use maven build with the command: spring-boot:run.

If you have any static files served by the system move them from src/main/webapp to src/main/resources/static (more info here: Static Content)

All of this should get your started with spring boot and allow you to remove applicationContext.xml while keeping best practices of spring boot. You could do it in an easier fashion but I think it will serve you better in the long run.

Upvotes: 0

Paul Samsotha
Paul Samsotha

Reputation: 209062

You're getting the error because the default way for Jersey to integrate with Spring is to look for this applicationContext.xml file. If you want to go xml-less, you need to configure Spring programmatically with a WebApplicationInitializer

@Order(1)
public class SpringWebContainerInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        registerContextLoaderListener(servletContext);

        // Set the Jersey used property so it won't load a ContextLoaderListener
        // see bug report https://java.net/jira/browse/JERSEY-2038
        servletContext.setInitParameter("contextConfigLocation", "");
    }

    private void registerContextLoaderListener(ServletContext servletContext) {
        WebApplicationContext webContext;
        webContext = createWebAplicationContext(SpringAnnotationConfig.class);
        servletContext.addListener(new ContextLoaderListener(webContext));
    }

    public WebApplicationContext createWebAplicationContext(Class... configClasses) {
        AnnotationConfigWebApplicationContext context;
        context = new AnnotationConfigWebApplicationContext();
        context.register(configClasses);
        return context;
    }
}

In this example, where you see

createWebAplicationContext(SpringAnnotationConfig.class)

Just use your AppConfig there.

What we're doing here is loading the Spring context ourselves, and when Jersey looks for it, it will find it, and not try to load the context itself (where it would otherwise try to find the applicationContext.xml file).

See also:

Upvotes: 3

Related Questions