Search code examples
spring-bootembedded-tomcat-8spring-boot-maven-plugin

Spring Boot web app not starting


I have a small spring boot app which exposes an API through a controller. The controller uses some services, which user mongodb repositories.

My pom.xml:

<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.springboot.testapp</groupId>
<artifactId>event-api</artifactId>
<version>1.0.0-SNAPSHOT</version>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.1.RELEASE</version>
</parent>

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <!-- MONGO DB -->
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-mongodb</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
</dependencies>

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

The controller:

@Controller
public class EventController {

    @Autowired
    private EventService eventService;

    @Autowired
    private EventAttendantService eventAttendantService;

    @Autowired
    private EventDayService eventDayService;

    @GetMapping(value = "/event/{id}")
    @ResponseBody
    public Event getEventById(@PathVariable Long id) {
        return eventService.getEventById(id);
    }

    @GetMapping(value = "/eventDays")
    @ResponseBody
    public List<EventDay> getEventDays() {
        return eventDayService.getAllEventDays();
    }

    @GetMapping(value = "/eventDay/{id}")
    @ResponseBody
    public List<Event> getEventsForDay(@PathVariable Long eventDayId) {
        EventDay eventDay = eventDayService.findById(eventDayId);

        List<Event> events = eventDay.getEvents()
                .stream()
                .map(id -> eventService.getEventById(id))
                .collect(Collectors.toList());

        events.sort(new Comparator<Event>() {
            @Override
            public int compare(Event o1, Event o2) {
                return o1.getStartTime().compareTo(o2.getStartTime());
            }
        });

        return events;
    }

    @GetMapping(value = "/event/{id}/attendants")
    @ResponseBody
    public List<EventAttendant> getAttendantsForEvent(@PathVariable Long eventId) {
        Event event = eventService.getEventById(eventId);

        return event.getAttendants()
                .stream()
                .map(id -> eventAttendantService.getById(id))
                .collect(Collectors.toList());
    }

    @PostMapping(value = "/eventDay")
    @ResponseBody
    public EventDay createEventDay(@RequestParam(value = "date") String date) {
        return eventDayService.createEventDay(date);
    }

    @DeleteMapping(value = "/eventDay/{eventDayId}")
    public void removeEventDay(@PathVariable(value = "eventDayId") Long eventDayId) {
        EventDay eventDay = eventDayService.findById(eventDayId);

        eventDay.getEvents()
                .stream()
                .forEach(eventId -> eventService.deleteEvent(eventId));

        eventDayService.removeEventDay(eventDayId);
    }

    @PostMapping(value = "/event")
    @ResponseBody
    public Event createEvent(@RequestParam(value = "eventDayId") Long eventDayId,
            @RequestParam(value = "name") String name,
            @RequestParam(value = "description") String description,
            @RequestParam(value = "location") String location,
            @RequestParam(value = "startTime") String startTime,
            @RequestParam(value = "endTime") String endTime) {
        Event event = eventService.createEvent(name, description, location, startTime, endTime);

        eventDayService.addEvent(eventDayId, event.getId());

        return event;
    }

    @DeleteMapping(value = "/event/{eventId}")
    @ResponseBody
    public void removeEvent(@PathVariable(value = "eventId") Long eventId) {
        List<EventDay> allEventDays = eventDayService.getAllEventDays();
        Optional<EventDay> eventDayForEvent = allEventDays.stream()
                .filter(eventDay -> eventDay.getEvents().contains(eventId))
                .findFirst();

        if (eventDayForEvent.isPresent()) {
            eventDayService.removeEvent(eventId, eventDayForEvent.get().getId());
        }
    }

    @PostMapping(value = "/attendant")
    @ResponseBody
    public EventAttendant createAttendant(@RequestParam(value = "firstName") String firstName,
            @RequestParam(value = "lastName") String lastName) {

        return eventAttendantService.create(firstName, lastName);
    }

    @PostMapping("/event/assign")
    public void assignAttendant(@RequestParam(value = "eventId") Long eventId,
            @RequestParam(value = "attendantId") Long attendantId) {

        eventService.addAttendant(eventId, attendantId);
    }

    @PostMapping("/event/remove")
    public void removeAttendant(@RequestParam(value = "eventId") Long eventId,
            @RequestParam(value = "attendantId") Long attendantId) {

        eventService.removeAttendant(eventId, attendantId);
    }
}

The main application class:

@SpringBootApplication(scanBasePackages = "com.springboot.test")
public class EventsAPI {

    private static final Logger LOG = LoggerFactory.getLogger(EventsAPI .class);

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

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setPort(9000);
        factory.setSessionTimeout(10, TimeUnit.MINUTES);
        return factory;
    }
}

When I run mvn spring-boot:run from the command line or from Eclipse I get all sort of errors. If I remove the "servletContainer" method, I get:

org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.

If it's there, I get another error:

Caused by: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletContainer' defined in com.centric.centricexpress.CentricExpressAPI: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.context.embedded.EmbeddedServletContainerFactory]: Factory method 'servletContainer' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/catalina/LifecycleListener

Maven is adding tomcat-embed-core-8.5.11 to the dependencies, so that class that is reported as not being found exists. This is very confusing for me.

I also tried some demo projects that I found on the Internet, but I can't manage to get any spring-boot application up and running, with an embedded container listening for requests.

Could somebody point out what I'm doing wrong?

Many thanks.


Solution

  • The ClassNotFoundException is a problem with your env. The org/apache/catalina/LifecycleListener class is part of the org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.11 which is a dependency of org.springframework.boot:spring-boot-starter-web:jar:1.5.1.RELEASE as shown below in the full dependency tree of your project (mvn dependency:tree).

    Please run mvn clean spring-boot:run

    [INFO] +- org.mongodb:mongo-java-driver:jar:3.4.1:compile
    [INFO] +- org.springframework.data:spring-data-mongodb:jar:1.10.0.RELEASE:compile
    [INFO] |  +- org.springframework:spring-tx:jar:4.3.6.RELEASE:compile
    [INFO] |  +- org.springframework:spring-context:jar:4.3.6.RELEASE:compile
    [INFO] |  |  \- org.springframework:spring-aop:jar:4.3.6.RELEASE:compile
    [INFO] |  +- org.springframework:spring-beans:jar:4.3.6.RELEASE:compile
    [INFO] |  +- org.springframework:spring-core:jar:4.3.6.RELEASE:compile
    [INFO] |  +- org.springframework:spring-expression:jar:4.3.6.RELEASE:compile
    [INFO] |  +- org.springframework.data:spring-data-commons:jar:1.13.0.RELEASE:compile
    [INFO] |  +- org.slf4j:slf4j-api:jar:1.7.22:compile
    [INFO] |  \- org.slf4j:jcl-over-slf4j:jar:1.7.22:compile
    [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
    [INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.5.1.RELEASE:compile
    [INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.5.1.RELEASE:compile
    [INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.5.1.RELEASE:compile
    [INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.1.RELEASE:compile
    [INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.1.RELEASE:compile
    [INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.9:compile
    [INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.1.9:compile
    [INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.22:compile
    [INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.22:compile
    [INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime
    [INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.1.RELEASE:compile
    [INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.11:compile
    [INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.11:compile
    [INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.11:compile
    [INFO] |  +- org.hibernate:hibernate-validator:jar:5.3.4.Final:compile
    [INFO] |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
    [INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
    [INFO] |  |  \- com.fasterxml:classmate:jar:1.3.3:compile
    [INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.6:compile
    [INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
    [INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.6:compile
    [INFO] |  +- org.springframework:spring-web:jar:4.3.6.RELEASE:compile
    [INFO] |  \- org.springframework:spring-webmvc:jar:4.3.6.RELEASE:compile
    [INFO] \- org.springframework.boot:spring-boot-starter-data-mongodb:jar:1.5.1.RELEASE:compile
    [INFO]    \- org.mongodb:mongodb-driver:jar:3.4.1:compile
    [INFO]       +- org.mongodb:mongodb-driver-core:jar:3.4.1:compile
    [INFO]       \- org.mongodb:bson:jar:3.4.1:compile