Springboot: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean [duplicate] - spring

I have a spring-boot application that needs to:
Be deployable as a war in a servlet container
Be runnable via `mvn spring-boot:run``
I'd also like to be able to run this application in my IDE (Eclipse or IntelliJ IDEA Community) by right clicking on the main and running it.
Here are the interesting parts of my pom.xml (Note that I do not inherit from spring-boot-starter-parent pom):
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Here's my SpringBootServletInitializer:
#Configuration
#EnableAutoConfiguration
#ComponentScan("com.company.theproject")
public class Application extends SpringBootServletInitializer
{
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(Application.class);
}
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
When running the main inside an IDE I get the following error:
org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:183) ~[spring-boot-1.2.3.RELEASE.jar:1.2.3.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:156) ~[spring-boot-1.2.3.RELEASE.jar:1.2.3.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:130) ~[spring-boot-1.2.3.RELEASE.jar:1.2.3.RELEASE]
... 12 common frames omitted
Seems like mvn spring-boot:run does some more magic that does not happen when running the main directly.
Removing the provided scope from the spring-boot-starter-tomcat dependency fixes this issue but causes trouble when the war is run inside a servlet container.
Right now the only "fix" I've found is to run mvn spring-boot:run within IntelliJ IDEA instead of running the main directly. While this is an acceptable workaround, I'd still like to know why this doesn't work and if it can be fixed.

A workaround that is strongly inspired from https://youtrack.jetbrains.com/issue/IDEA-140041 is to start your main class with the test classpath (which includes the embedded servlet.)
Steps (IntelliJ 16):
Run -> Edit Configurations -> Add new configuration -> Pick Application type.
Set Main class to <your.main.class>
Set Use classpath of module to <*>_test (the test module!)
Ok and Run it!

I believe this could be related to https://youtrack.jetbrains.com/issue/IDEA-107048
IntelliJ IDEA is not injecting the provided dependencies into the CLASSPATH and as Andy stated this is why spring is unable to create the embedded servlet container.
They have a feature request since 2005 about this: https://youtrack.jetbrains.com/issue/IDEABKL-99
Workarounds mentioned in the comments includes having a fake module with the necessary libs and using it as classpath, using the -Xbootclasspath JVM argument or using custom maven profiles for running (compiled) vs building (provided).

I had the same problem using IntelliJ 2018.
Initially, Make sure that you have added the maven library for the spring project in your IntelliJ.
My solution is:
Go to Run -> Edit Configurations.
Select Application && choose your current project.
Check Include dependencies with "Provided" scope.
OK -> RUN

I was able to make this work by changing the scope of the spring-boot-starter-tomcat dependency to "compile" under Project structure->Dependencies tab. This doesn't effect pom.xml but allows this dependencies to be available to spring boot run configuration
Click here for image on where to change this setting in idea

mvn spring-boot:run includes provided dependencies when it's creating the classpath. It sounds like IntelliJ IDEA does not. Without Tomcat on the classpath, Spring Boot's unable to create an embedded servlet container which causes the exception you're seeing. Arguably this is a bug in IntelliJ as, if there's no container to provide the dependency, then it really needs to be on the classpath.
You may be able to fix the problem by overriding the default classpath that IntelliJ uses when running the main method to include the spring-boot-starter-tomcat dependency.

I find this page, and use the maven profile to manage the profiles.
<profiles>
<profile>
<id>PROD</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>DEV</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>TEST</scope>
</dependency>
</dependencies>
</profile>
</profiles>
and config the main class beforeLanuce,set the command
mvn clean compile -Pdev

I was able to work around this problem in Intellij IDEA 2017.2 by adding the provided libaray (spring-boot-starter-tomcat) to the project configuration.
Select File -> Project Structure. Select Libraries and add a new project library (type = From Maven...). Search for spring-boot-starter-tomcat using the dialog, select the correct version and add it by clicking on OK. The library is added to the list of external libraries.
The disadvantage is that if the Spring Boot version is changed then you will have to remember to delete this library and add the new version.

Using the profile and instructions below, you can add a profile to maven that allows development in IntelliJ without changing things for other environments.
<!-- Leave original dependency as-is -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<profiles>
<!-- Enable this profile to run in IntelliJ. IntelliJ excludes provided dependencies from compile by default. -->
<profile>
<id>intellij</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
</profile>
</profiles>
Click the Maven Projects button on the right side of IntelliJ, and under Profiles, select intellij.

Follow these steps:
On the top right side of intellij window, click the drop down and select edit configuration and a new window will open.
In this window, on top left side, click "+" button and select sprint boot.
Then add you main class, and other details as shown in screenshot.
Now Run the application.

Related

Maven Jetty plugin configure repository

We use jetty plugin for local deployment of our application. Recently i added a repository in the pom and added dependencies both in the plugin section and the dependencies section outside as well, when i build the war and deploy it on standalone app server everything works ok, however the same application when i try to run through the jetty application it throws me error for that particular dependency.
Is there any way that we can configure the external repositories to be used by the plugins in order to resolve the dependencies.
Thanks,
- Vaibhav
If I understand your issue right, you can add a dependency to the jetty-maven-plugin itself and have it available to your application. Something like this:
<plugin>
<groupId>org.eclipse.jetty.maven</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.14.v20161028</version>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
</plugin>

How do I get SpringLoaded to work with Maven in IntelliJ (or on the commandline)?

I have a project that will run fine with mvn spring-boot:run, and I would like the ability to hot swap automatically after compiling. I setup the dependency as follows:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.2.5.RELEASE</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
</dependencies>
</plugin>
However, I'm not seeing changes in response to a recompile. Is something more needed?
Spring loaded will hot swap only when you update your classes i.e. you build the project, it won't do the recompilation for you.
In case of intellij you need to hit Ctrl+F9 (or its equivalent on mac), or enable ‘Make Project Automatically’ to automatically compile your code whenever a file is saved.

Add external library .jar to Spring boot .jar internal /lib

I have an external .jar that cannot be imported from public repositories using pom.xml, it's sqljdbc41.jar.
I can run the project locally from my IDE, and everything will work. I referenced the library after downloading it like so:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/sqljdbc41.jar</systemPath>
</dependency>
When I run mvn clean package to create my .jar file and try to run the created .jar, a mistake will pop up, which mentions the SQL Server references are not valid. I then extracted my .jar file and true enough, everything that is referenced in the pom.xml file properly gets downloaded and added, however, my SQL Server does not.
I can, in a very hacky way* just manually add the sqljdbc41.jar to my /lib folder after it's been compiled as a .jar, and it'll work, however that seems highly unoptimal. What would be a better approach?
*Opening the .jar file with Winrar, going to the /lib folder, manually selecting my sqljdbc41.jar file, then make sure to select the No Compression option bottom left where Winrar gives you compression options, in case you find this by Google and no one answered.
you can set 'includeSystemScope' to true.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
You could install the sqljdbc41.jar in your local repository :
mvn install:install-file -Dfile=path/to/sqljdbc41.jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc41 -Dversion=4.1 -Dpackaging=jar
And then declare the dependency as a standard dependency :
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
</dependency>
If you use a remote artifact repository (nexus, archiva...) you also need to deploy the artifact on this repository. You can find more here : https://maven.apache.org/guides/mini/guide-3rd-party-jars-remote.html
Another way, you can put it into the resources folder, such as resources/lib/xxx.jar, then config the pom.xml like this:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/sqljdbc41.jar</systemPath>
</dependency>
In Spring Boot: I also faced similar issue and below code helped me.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.7.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
It works for me:
project {root folder}/libs/ojdbc-11.2.0.3.jar
pom.xml:
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>11.2.0.3</version>
<scope>system</scope>
<systemPath>${basedir}/libs/ojdbc-11.2.0.3.jar</systemPath>
</dependency>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
In my case, the fault was providing a version number without "dot" in tag:
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1</version>
<systemPath>${basedir}/src/main/resources/lib/tools.jar</systemPath>
</dependency>
This one works:
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1.8</version>
<systemPath>${basedir}/src/main/resources/lib/tools.jar</systemPath>
</dependency>
When Spring-Boot projects are used with maven or gradle plugins they packaged the applicaiton by default as executable jars.
These executable jars cannot be used as dependency in any another Spring-Boot project because the executable jar add classes in BOOT-INF/classes folder. This means that they cannot be found when the executable jar is used as a dependency because the dependency jar will also have the same class path structure as shown below.
If we want to use project-A as a maven dependency in project-B then we must have two artifacts. To produce the two artifacts, one that can be used as a dependency and one that is executable, a classifier must be specified. This classifier is applied to the name of the executable archive, leaving the default archive for use as a dependency.
To configure a classifier of exec in Maven, you can use the following configuration:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
So the MAJIC WORD here is <classifier>exec</classifier> this will create a jar structure as below and then it could easily be conusmed by spring-boot project as maven dependency jar on class path.
The above plugin need to be add in project-A pom that is going to be used as dependency in project-B. Same is explained in spring documentation section 16.5. as well.
In order to work through the local repository, the target .jar file that we will work with must be in the s2 folder. Several methods can be used for this:
The file can be taken manually and put in the relevant place (not
preferred). The same process can be done by installing it via the
console.
Relevant Remote URL is written in the .pom file dependencies and
automatically places it in the s2 folder when Intellij is refreshed
(validate) in the IDE used.
The same process can be done by addressing the .pom file dependencies via the centeral repository.
Attention: ComponentScan should not be forgotten for the related jar work on SpringBot.

Spring Loaded not picking up changes (Run via Command Line / Edit using IntelliJ)

I have a very basic Spring Boot application that i use to run inside a terminal windows using.
mvn clean spring-boot:run
To use Spring Loaded i have modified my pom.xml to auto attach the reloading agent.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
In the console window i see that the reloading agent is attached.
But when i open the Maven Project inside IntelliJ and modify some code the reloading does not take place. I tried to manually compile the modified classes but this also seems not to have any effect.
What am i missing??
It seemed that Java 8 Update 40 broke the compatibility. So a downgrade to Java 8 Update 31 solved the issue.

How to define a dependency scope in maven to include a library in compile, run, test, but not in assembly/packaging?

I'm building an Apache Spark application that can both be debugged locally and deployed to cluster. To do this, I have to define its dependency to spark-core (a Java/scala library) to fulfil the following requirement.
Included in in compile (other wise the compilation fails)
Included in run and test (for local debugging and unit test)
Excluded in assembly (for deployment to a cluster with provided spark-core, this decrease jar size by 70M, I'm using maven-shade plugin to generate the all-inclusive jar as there are some jar hell issues that cannot be resolved using maven-assembly)
Unfortunately it looks like custom scope wasn't natively supported by maven. Is there a way to enable it using some plugins?
We do exactly that on our maven build: exclude the Spark assembly from being included in the job assembly. We add an exclusion rule to the maven-shade plugin configuration.
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jar-with-dependencies</shadedClassifierName>
<artifactSet>
<excludes>
<exclude>org.apache.spark:spark-assembly</exclude>
</excludes>
</artifactSet>
...
</configuration>
You can use the scope attribute (provided) for dependency.
This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
Ref : http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope
eg:
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-b</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>provided</scope>
</dependency>
You should create 2 profiles. 1 for your idea with spark at compile scope (default), the other used during your build (with provided scope).
<profiles>
<profile>
<id>default-without-spark</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>dev</id>
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
You'll get what you want without the disadvantage of #maasg solution (all spark transitive dependencies added to your final jar)

Resources