diff --git a/pom.xml b/pom.xml
index 8fa402b69e..bc8e35ba94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -231,6 +231,8 @@
spring-zuul
spring-reactor
spring-vertx
+
+ spring-rest-embedded-tomcat
testing
diff --git a/spring-rest-embedded-tomcat/pom.xml b/spring-rest-embedded-tomcat/pom.xml
new file mode 100644
index 0000000000..554040e763
--- /dev/null
+++ b/spring-rest-embedded-tomcat/pom.xml
@@ -0,0 +1,83 @@
+
+ 4.0.0
+ org.baeldung.embedded
+ SpringRestTomcat
+ 0.0.1-SNAPSHOT
+
+ spring-rest-embedded-tomcat
+ war
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+ org.springframework
+ spring-core
+ ${spring.version}
+
+
+ org.springframework
+ spring-webmvc
+ ${spring.version}
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.0
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.library}
+
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-core
+ 9.0.1
+ test
+
+
+
+ org.apache.tomcat
+ tomcat-jasper
+ 9.0.1
+ test
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.3
+
+
+
+ org.apache.httpcomponents
+ httpcore
+ 4.4.8
+
+
+
+
+
+ spring-rest-embedded-tomcat
+
+
+
+ 5.0.1.RELEASE
+ 4.12
+ 2.9.2
+ 1.8
+ 1.8
+ false
+
+
+
\ No newline at end of file
diff --git a/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/AppInitializer.java b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/AppInitializer.java
new file mode 100644
index 0000000000..24bd28166b
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/AppInitializer.java
@@ -0,0 +1,22 @@
+package org.baeldung.embedded.configuration;
+
+import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
+
+public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
+
+ @Override
+ protected Class>[] getRootConfigClasses() {
+ return new Class[] { UserConfiguration.class };
+ }
+
+ @Override
+ protected Class>[] getServletConfigClasses() {
+ return null;
+ }
+
+ @Override
+ protected String[] getServletMappings() {
+ return new String[] { "/" };
+ }
+
+}
diff --git a/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/UserConfiguration.java b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/UserConfiguration.java
new file mode 100644
index 0000000000..4c102a74cb
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/configuration/UserConfiguration.java
@@ -0,0 +1,12 @@
+package org.baeldung.embedded.configuration;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@Configuration
+@EnableWebMvc
+@ComponentScan(basePackages = "org.baeldung.embedded")
+public class UserConfiguration {
+
+}
diff --git a/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/controller/UserController.java b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/controller/UserController.java
new file mode 100644
index 0000000000..a9a5faa0c6
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/controller/UserController.java
@@ -0,0 +1,28 @@
+package org.baeldung.embedded.controller;
+
+import org.baeldung.embedded.domain.User;
+import org.baeldung.embedded.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class UserController {
+
+ @Autowired
+ UserService userService;
+
+ @RequestMapping("/")
+ public String welcome() {
+ return "Hello World!";
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/user/{userName}")
+ @ResponseBody
+ public User user(@PathVariable String userName) {
+ return this.userService.getUser(userName);
+ }
+}
diff --git a/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/domain/User.java b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/domain/User.java
new file mode 100644
index 0000000000..2f9443daea
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/domain/User.java
@@ -0,0 +1,23 @@
+package org.baeldung.embedded.domain;
+
+public class User {
+
+ private String name;
+ private String hobby;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getHobby() {
+ return hobby;
+ }
+
+ public void setHobby(String hobby) {
+ this.hobby = hobby;
+ }
+}
diff --git a/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/service/UserService.java b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/service/UserService.java
new file mode 100644
index 0000000000..76696e12c2
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/main/java/org/baeldung/embedded/service/UserService.java
@@ -0,0 +1,38 @@
+package org.baeldung.embedded.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.baeldung.embedded.domain.User;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserService {
+ private List users = new ArrayList<>();
+
+ public void addUser(String name) {
+ User user = new User();
+ user.setName(name);
+ if (name == "HarryPotter") {
+ user.setHobby("Quidditch");
+ } else {
+ user.setHobby("MuggleActivity");
+ }
+ users.add(user);
+ }
+
+ public User getUser(String name) {
+ for (User user : users) {
+ if (user.getName()
+ .equalsIgnoreCase(name)) {
+ return user;
+ }
+ }
+
+ User user = new User();
+ user.setName(name);
+ user.setHobby("None");
+
+ return user;
+ }
+}
diff --git a/spring-rest-embedded-tomcat/src/main/webapp/emptyFile b/spring-rest-embedded-tomcat/src/main/webapp/emptyFile
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatApp.java b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatApp.java
new file mode 100644
index 0000000000..f340f6c837
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatApp.java
@@ -0,0 +1,70 @@
+package org.baeldung.embedded;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+public class EmbeddedTomcatApp {
+
+ private Tomcat tomcatInstance;
+ private WebApplicationContext webApplicationContext;
+ private CountDownLatch started = new CountDownLatch(1);
+
+ public void start() throws Exception {
+ tomcatInstance = new Tomcat();
+ tomcatInstance.setBaseDir(new File(getClass().getResource(".")
+ .toURI()).getAbsolutePath()); // Tomcat's temporary directory
+ tomcatInstance.setPort(0);
+
+ Context webapp = tomcatInstance.addWebapp("", new File("src/main/webapp/").getAbsolutePath());
+
+ webapp.addLifecycleListener(event -> {
+ if (event.getType()
+ .equals("after_stop")) {
+ started.countDown();
+ } else if (event.getType()
+ .equals("after_start")) {
+ webApplicationContext = WebApplicationContextUtils
+ .findWebApplicationContext(webapp.getServletContext());
+
+ ((ConfigurableListableBeanFactory) webApplicationContext
+ .getAutowireCapableBeanFactory()).registerSingleton("baseUrl", getBaseUrl());
+
+ started.countDown();
+ }
+ });
+
+ tomcatInstance.start();
+ started.await();
+ }
+
+ public Tomcat getTomcatInstance() {
+ return this.tomcatInstance;
+ }
+
+ public String getBaseUrl() {
+ return String.format("http://localhost:%d%s", getLocalPort(), getWebApplicationContext().getServletContext()
+ .getContextPath());
+ }
+
+ public int getLocalPort() {
+ return tomcatInstance.getConnector()
+ .getLocalPort();
+ }
+
+ public WebApplicationContext getWebApplicationContext() {
+ return webApplicationContext;
+ }
+
+ public boolean isStarted() {
+ return started.getCount() == 0;
+ }
+
+ public boolean isStartedSucessfully() {
+ return webApplicationContext != null;
+ }
+}
diff --git a/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatRunner.java b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatRunner.java
new file mode 100644
index 0000000000..1bf15556e8
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/EmbeddedTomcatRunner.java
@@ -0,0 +1,45 @@
+package org.baeldung.embedded;
+
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+public class EmbeddedTomcatRunner extends BlockJUnit4ClassRunner {
+
+ public EmbeddedTomcatRunner(Class> klass) throws InitializationError {
+ super(klass);
+ }
+
+ // use one static Tomcat instance shared across all tests
+ private static EmbeddedTomcatApp embeddedTomcatApp = new EmbeddedTomcatApp();
+
+ @Override
+ protected Statement classBlock(RunNotifier notifier) {
+ ensureSharedTomcatStarted();
+ Statement result = super.classBlock(notifier);
+ return result;
+ }
+
+ private void ensureSharedTomcatStarted() {
+ if (!embeddedTomcatApp.isStarted()) {
+ try {
+ embeddedTomcatApp.start();
+ } catch (Exception e) {
+ throw new RuntimeException("Error while starting embedded Tomcat server", e);
+ }
+ }
+ }
+
+ @Override
+ protected Object createTest() throws Exception {
+ if (!embeddedTomcatApp.isStartedSucessfully()) {
+ throw new RuntimeException("Tomcat server not started successfully. Skipping test");
+ }
+ Object testInstance = super.createTest();
+ embeddedTomcatApp.getWebApplicationContext()
+ .getAutowireCapableBeanFactory()
+ .autowireBean(testInstance);
+ return testInstance;
+ }
+}
\ No newline at end of file
diff --git a/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/UserIntegrationTest.java b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/UserIntegrationTest.java
new file mode 100644
index 0000000000..1c5d482171
--- /dev/null
+++ b/spring-rest-embedded-tomcat/src/test/java/org/baeldung/embedded/UserIntegrationTest.java
@@ -0,0 +1,60 @@
+package org.baeldung.embedded;
+
+import java.io.IOException;
+import java.util.Map;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.baeldung.embedded.service.UserService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@RunWith(EmbeddedTomcatRunner.class)
+public class UserIntegrationTest {
+
+ @Autowired
+ protected String baseUrl;
+
+ @Autowired
+ private UserService userService;
+
+ private String userName = "HarryPotter";
+
+ @Before
+ public void setUp() {
+ userService.addUser(userName);
+ }
+
+ @Test
+ public void givenUserName_whenSendGetForHarryPotter_thenHobbyQuidditch() throws IOException {
+ String url = baseUrl + "/user/" + userName;
+
+ HttpClient httpClient = HttpClientBuilder.create()
+ .build();
+ HttpGet getUserRequest = new HttpGet(url);
+ getUserRequest.addHeader("Content-type", "application/json");
+ HttpResponse response = httpClient.execute(getUserRequest);
+
+ Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine()
+ .getStatusCode());
+
+ HttpEntity responseEntity = response.getEntity();
+
+ Assert.assertNotNull(responseEntity);
+
+ ObjectMapper mapper = new ObjectMapper();
+ String retSrc = EntityUtils.toString(responseEntity);
+ Map result = mapper.readValue(retSrc, Map.class);
+
+ Assert.assertEquals("Quidditch", result.get("hobby"));
+ }
+}