How to register an object in jersey 2(ResourceConfig)

eigenharsha picture eigenharsha · Mar 17, 2017 · Viewed 10k times · Source

I want to register a class component(Object) in jersey not class reference. I create a XYZResource class that be called by main() method and it be configured through jersey with DBI object. DAOService daoService has connection DBI connection and the getDetails() that execute query and return result.

I use IntelliJ IDE and run through Main Class com.example.Main

when i hit my url http://localhost:9000/resource/test than it through error

javax.servlet.ServletException: A MultiException has 1 exceptions.  They are:
1. java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.

    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:392)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)
root cause

A MultiException has 1 exceptions.  They are:
1. java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.

    org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:88)
    org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:852)
    org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
    org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
    org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
    org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:174)
    org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
    org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
    org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
    org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
    org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
    org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
    org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)
root cause

java.lang.NoSuchMethodException: Could not find a suitable constructor in com.example.AdminResource class.
    org.glassfish.jersey.internal.inject.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:189)
    org.jvnet.hk2.internal.Utilities.getConstructor(Utilities.java:159)
    org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:850)
    org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
    org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
    org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
    org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:174)
    org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
    org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
    org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
    org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
    org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
    org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
    org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
    org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:535)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:483)
    org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:420)

Technology Use:

  • Java - 8
  • Embedded tomcat - 8
  • Jersey 2.5.1 (REST)
  • JDBI 2.63.1 (DB Service)

Main.java

package com.example;

import com.core.db.DAOService;
import com.example.servlets.HelloWorldServlet;
import com.example.util.abc;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.skife.jdbi.v2.DBI;

public class Main {

public static void main (String[] args) {
    Tomcat tomcat = new Tomcat();
    tomcat.setPort(9000);

    String baseDoc = new File("src/main/webapp").getAbsolutePath();
    Context ctx = tomcat.addContext("/servletSample", baseDoc);

    tomcat.addWebapp(null, "", baseDoc);
    tomcat.addServlet(ctx, "HelloWorld", new HelloWorldServlet());
    ctx.addServletMapping("/*", "HelloWorld");

    try { 

        final DBI XYZDBI = new DBI(/*url*/, /*username*/, /*password*/);
        /* DAOService is a class that has function getDetails() that retrive   data from database */
        final DAOService daoService = XYZDBI.onDemand(DAOService.class);
        final org.glassfish.jersey.server.ResourceConfig jerseyResource = new org.glassfish.jersey.server.ResourceConfig();

        /* Register XYZResource class instance with jersey Resouce */
        jerseyResource.register(new XYZResource(daoService));

        tomcat.start();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }

        while (true) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>my-jersey</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<build>
    <finalName>my-embed-tomcat</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <inherited>true</inherited>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
   <!-- Dependencies for Jersey Web Application -->
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-servlet-api</artifactId>
        <version>7.0.42</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-mvc-jsp</artifactId>
        <version>2.5.1</version>
    </dependency>

   <!-- Dependencies for Embedded Tomcat -->
   <dependency>
       <groupId>org.apache.tomcat.embed</groupId>
       <artifactId>tomcat-embed-core</artifactId>
       <version>8.0.26</version>
   </dependency>
   <dependency>
       <groupId>org.apache.tomcat.embed</groupId>
       <artifactId>tomcat-embed-logging-juli</artifactId>
       <version>8.0.26</version>
   </dependency>
   <dependency>
       <groupId>org.apache.tomcat.embed</groupId>
       <artifactId>tomcat-embed-jasper</artifactId>
       <version>8.0.26</version>
   </dependency>

   <dependency>
       <!--org.skife.jdbi.v2-->
       <groupId>org.jdbi</groupId>
       <artifactId>jdbi</artifactId>
       <version>2.63.1</version>
   </dependency>
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <version>1.7.7</version>
   </dependency>

   <dependency>
       <groupId>com.fasterxml.jackson.dataformat</groupId>
       <artifactId>jackson-dataformat-yaml</artifactId>
       <version>2.8.0.rc2</version>
   </dependency>
   <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>2.8.3</version>
   </dependency>
   <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-core</artifactId>
       <version>2.8.0.rc2</version>
   </dependency>
   <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
       <version>2.8.0.rc2</version>
   </dependency>
   <dependency>
       <groupId>microsoft.com</groupId>
       <artifactId>sqlJdbc4</artifactId>
       <version>4.0.2206.100</version>
   </dependency>
   <dependency>
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
       <version>2.6</version>
   </dependency>
</dependencies>


XYZResource.java

package com.example;

import com.core.db.DAOService;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;

@Path("resource")
public class XYZResource {

    private final DAOService daoService;

    public XYZResource(DAOService daoService) {
        this.daoService = daoService;        
    }

    @GET
    public String helloworld() {
        return "User - Resource";
    }

    @GET
    @Path("/test")
    public Response test() {
        Set<String> User = daoService.getDetails();
        Iterator<String> itr = User.iterator();
        return Response.status(200).entity(itr.next().toString())
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "GET")
                .build();
        }
    }
}

MyApplication.java

package com.example;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;

public class MyApplication extends ResourceConfig {

    public MyApplication() {

        this.packages(MyApplication.class.getPackage().getName()).register(JspMvcFeature.class);
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
    <display-name>Jersey Jersey Application</display-name>

    <filter>
        <filter-name>Jersey Application Filter</filter-name>
        <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.example.MyApplication</param-value>
        </init-param>
        <!-- pass to next filter if Jersey/App returns 404 -->
        <init-param>
            <param-name>jersey.config.servlet.filter.forwardOn404</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>Jersey Application Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Update

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>jersey-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <build>
        <finalName>my-embed-tomcat</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <tomcat.version>8.0.28</tomcat.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


   <dependencies>
s
       <dependency>
           <groupId>org.glassfish.jersey.bundles.repackaged</groupId>
           <artifactId>jersey-guava</artifactId>
           <version>2.25.1</version>
       </dependency>

       <!-- Dependencies for Jersey Web Application -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-servlet-api</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-mvc-jsp</artifactId>
            <version>2.5.1</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
       <dependency>
           <groupId>org.glassfish.jersey.containers</groupId>
           <artifactId>jersey-container-servlet</artifactId>
           <version>2.5.1</version>
       </dependency>
       <!-- Dependencies for Embedded Tomcat -->
       <dependency>
           <groupId>org.apache.tomcat.embed</groupId>
           <artifactId>tomcat-embed-core</artifactId>
           <version>${tomcat.version}</version>
       </dependency>
       <dependency>
           <groupId>org.apache.tomcat.embed</groupId>
           <artifactId>tomcat-embed-logging-juli</artifactId>
           <version>${tomcat.version}</version>
       </dependency>
       <dependency>
           <groupId>org.apache.tomcat.embed</groupId>
           <artifactId>tomcat-embed-jasper</artifactId>
           <version>${tomcat.version}</version>
       </dependency>

       <dependency>
           <!--org.skife.jdbi.v2-->
           <groupId>org.jdbi</groupId>
           <artifactId>jdbi</artifactId>
           <version>2.63.1</version>
       </dependency>
       <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-api</artifactId>
           <version>1.7.7</version>
       </dependency>

       <dependency>
           <groupId>com.fasterxml.jackson.dataformat</groupId>
           <artifactId>jackson-dataformat-yaml</artifactId>
           <version>2.8.0.rc2</version>
       </dependency>
       <dependency>
           <groupId>com.fasterxml.jackson.core</groupId>
           <artifactId>jackson-databind</artifactId>
           <version>2.8.3</version>
       </dependency>
       <dependency>
           <groupId>com.fasterxml.jackson.core</groupId>
           <artifactId>jackson-core</artifactId>
           <version>2.8.0.rc2</version>
       </dependency>
       <dependency>
           <groupId>com.fasterxml.jackson.core</groupId>
           <artifactId>jackson-annotations</artifactId>
           <version>2.8.0.rc2</version>
       </dependency>
       <dependency>
           <groupId>microsoft.com</groupId>
           <artifactId>sqlJdbc4</artifactId>
           <version>4.0.2206.100</version>
       </dependency>
       <dependency>
           <groupId>commons-lang</groupId>
           <artifactId>commons-lang</artifactId>
           <version>2.6</version>
       </dependency>
    </dependencies>

</project>

Main.java

package com.example;

import org.apache.catalina.Context;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;

import javax.servlet.Filter;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.File;

/**
 * @author Paul Samsotha.
 */
public class Main {

    public static void main(String... args) throws Exception {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(9000);

        File base = new File(".");
        Context context = tomcat.addContext("", base.getAbsolutePath());

        Tomcat.addServlet(context, "default", new DefaultServlet());
        context.addServletMapping("/*", "default");

        final FilterDef def = new FilterDef();
        final FilterMap map = new FilterMap();

        def.setFilterName("jerseyFilter");
        def.setFilter(getJerseyFilter());
        context.addFilterDef(def);

        map.setFilterName("jerseyFilter");
        map.addURLPattern("/api/*");
        context.addFilterMap(map);

        tomcat.start();

        while (true) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static Filter getJerseyFilter() {
        final ResourceConfig config = new ResourceConfig()
                .register(new HelloResource(new Service()))
                .register(JspMvcFeature.class)
                .property(ServletProperties.FILTER_FORWARD_ON_404, true);
        return new ServletContainer(config);
    }

    public static class Service {
        public String getMessage() {
            return "Hello Tomcat!";
        }
    }

    @Path("tomcat")
    public static class HelloResource {
        private final Service service;

        public HelloResource (Service service) {
            this.service = service;
        }

        @GET
        public String get() {
            return this.service.getMessage();
        }
    }
}

Answer

Paul Samsotha picture Paul Samsotha · Mar 17, 2017

You seem to have a lot of unnecessary stuff going on. You have two different configurations. Pick one. The problem is caused by the package scanning, which is picking up the resource and trying to register it.

Just get rid of the web.xml and MyApplication and just use the ResourceConfig you're currently using in the main class. Then you can register the servlet programmatically using Jersey's ServletContainer which is both a Filter and a HttpServlet. So you don't need the web.xml to configure Jersey as Filter. The ServletContainer is already a Filter

new SevletContainer(youResourceConfig);

I'm not too familiar with Tomcat embedded so I can't say how to register filters, but I'm sure a quick search will find you the answer. Just register the ServletContainer as a filter.

The jersey.config.servlet.filter.forwardOn404 init-param can also be configured with the filter registration. Or you can just configure it with the ResourceConfig, with its property method

resourceConfig.property("jersey.config.servlet.filter.forwardOn404", true);

Or better yet, use the constant

property(ServletProperties.FILTER_FORWARD_ON_404, true);

UPDATE

Here is a complete setup (based on your example) that works.

import org.apache.catalina.Context;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;

import javax.servlet.Filter;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.File;

/**
 * @author Paul Samsotha.
 */
public class Main {

    public static void main(String... args) throws Exception {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(9000);

        File base = new File(".");
        Context context = tomcat.addContext("", base.getAbsolutePath());

        Tomcat.addServlet(context, "default", new DefaultServlet());
        context.addServletMapping("/*", "default");

        final FilterDef def = new FilterDef();
        final FilterMap map = new FilterMap();

        def.setFilterName("jerseyFilter");
        def.setFilter(getJerseyFilter());
        context.addFilterDef(def);

        map.setFilterName("jerseyFilter");
        map.addURLPattern("/api/*");
        context.addFilterMap(map);

        tomcat.start();

        while (true) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static Filter getJerseyFilter() {
        final ResourceConfig config = new ResourceConfig()
                .register(new HelloResource(new Service()))
                .register(JspMvcFeature.class)
                .property(ServletProperties.FILTER_FORWARD_ON_404, true);
        return new ServletContainer(config);
    }

    public static class Service {
        public String getMessage() {
            return "Hello Tomcat!";
        }
    }

    @Path("tomcat")
    public static class HelloResource {
        private final Service service;

        public HelloResource (Service service) {
            this.service = service;
        }

        @GET
        public String get() {
            return this.service.getMessage();
        }
    }
}

A few changes I made:

  1. Not sure why you are using Tomcat 7 Servlet API. I Changed that to the 8.x version of your other Tomcat dependencies.

  2. I also excluded the Servlet API from the Jersey MVC dependency, as that pulls in an older 2.4 Servlet API

    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-mvc-jsp</artifactId>
        <exclusions>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  3. I added a DefaultServlet to handle the pages. From testing (again I am not Tomcat expert), it seems this is required

With the example you should be able to GET

http://localhost:9000/api/tomcat