Search code examples
restjakarta-eejax-rsresteasywildfly-8

RESTEasy (jax-rs), multiple packages declaration in web.xml?


How to declare multiple packages in the web.xml for the RESTEasy jax-rs provider?

If I have:

enter image description here

 <web-app id="WebApp_ID" version="2.4"
        xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>Restful Web Application</display-name>

    <!-- this need same with resteasy servlet url-pattern -->
        <context-param>
            <param-name>resteasy.servlet.mapping.prefix</param-name>
            <param-value>/rest</param-value>
        </context-param>

        <servlet>
            <servlet-name>resteasy-servlet</servlet-name>
            <servlet-class> org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher </servlet-class>
            <init-param>
                <param-name>javax.ws.rs.Application</param-name>
                <param-value>part1.MessageApplication</param-value>
            </init-param>
        </servlet>

        <servlet-mapping>
            <servlet-name>resteasy-servlet</servlet-name>
            <url-pattern>/rest/*</url-pattern>
        </servlet-mapping>
    </web-app>

It's working.

But If I have :

enter image description here

And then change the declaration of the web.xml (which is based on this way, which may have already worked in Jersey)

<servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class> org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>part1.MessageApplication;part2.MessageApplication2</param-value>
        </init-param>
    </servlet>

Whenever I try to access a @Path-mapped-class in package "part2" it will throw :

java.lang.RuntimeException: java.lang.ClassNotFoundException: part1.MessageApplication;part2.MessageApplication2 from

Note that I'm aware that I've changed the @Path-mapped-class with different url path like @Path("controller2").

How do I configure it properly in the web.xml?


Solution

  • Not sure if I clearly understand your problem. The link you provided in your question is about specifying multiple packages. But looks like you are dealing with two Application subclasses. It's a different matter.

    In this situation, you should register two HttpServletDispatcher mapped to different URI patterns, as following:

    <!-- Application 1 (part1.MessageApplication) mapped to /rest/app1/* -->
    <servlet>
        <servlet-name>resteasy-application1</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>part1.MessageApplication</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>resteasy-application1</servlet-name>
        <url-pattern>/rest/app1/*</url-pattern>
    </servlet-mapping>
    
    <!-- Application 2 (part2.MessageApplication2) mapped to /rest/app2/* -->
    <servlet>
        <servlet-name>resteasy-application2</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>part2.MessageApplication2</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>resteasy-application2</servlet-name>
        <url-pattern>/rest/app2/*</url-pattern>
    </servlet-mapping>
    

    Each Application subclass is mapped to a path that serves as the base URI for the resource URIs provided by @Path annotation.

    You could have multiple Application subclasses when you support multiple versions of the API, for example. For simple applications, it's very likely you don't need that.

    You may not need a web.xml

    As per your comment, you are using WildFly 8. It's Servlet 3.0 compatible so you don't even need a web.xml deployment descriptor for simple applications. Most of the configurations, such as registering servlets, filters and listeners can be done via annotations.

    In case you are not providing a web.xml deployment descriptor for your Maven-based web application project, you need to configure your maven-war-plugin to ignore the missing web.xml file by setting the failOnMissingWebXml configuration property to false in your project pom.xml file:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
    </plugin>
    

    Since the version 3.0.0 of the maven-war-plugin, the default value for failOnMissingWebXml has been changed from true to false. You can use the most recent version and ommit that configuration property.

    If, for some reason, you want to keep the web.xml, it can be as simple as:

    <web-app 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_0.xsd"
              version="3.0">
    
    </web-app>
    

    A few words on the Application class

    Regarding JAX-RS, annotate your Application subclass with @ApplicationPath specifying the base URI for your resource classes:

    @ApplicationPath("api")
    public SampleApplication extends Application {
    
    }
    

    In the example above, the JAX-RS runtime will scan the classpath for JAX-RS components and will register them automatically.

    If you want to manually register your resources and providers (preventing the JAX-RS runtime from registering the components automatically), override the getClasses() and/or the getSingletons() methods:

    @ApplicationPath("api")
    public SampleApplication extends Application {
    
        @Override
        public Set<Class<?>> getClasses() {
            Set<Class<?>> resources = new HashSet<>();
            resources.add(MyResource.class);
            resources.add(MyOtherResource.class);
            return resources;
        }
    }
    

    For more details on the Application class, this answer can provide you some insights.

    Managing your dependencies

    It's worthwhile to mention that RESTEasy 3.x is shipped with WildFly. If you will use only the JAX-RS API the following dependency will give you all you need:

    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
    </dependency>
    

    If you need to use any type from the RESTEasy API, add the RESTEasy 3.x dependencies with the provided scope. It tells Maven that the container will provide that dependency, hence they won't be shipped with your application. Failing to provide the right scope may cause some weird errors and bad headaches. For more details on scopes, check the dependency scope documentation.