How is a war file created for spring boot with maven? - maven

I'm trying to follow the guide for converting a spring project to a war.
http://spring.io/guides/gs/convert-jar-to-war/
It starts out using maven and gradle and then right after the jar portion it completely forgets about maven and only has gradle updates.

There are two main changes that you need to make in the pom. The first is to change the project's packaging type to war:
<groupId>org.springframework</groupId>
<artifactId>gs-convert-jar-to-war</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
The second is to add a dependency on spring-boot-starter-tomcat and mark it as provided:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
mvn package will now produce a war file that can be run using java -jar or deployed to a separate servlet container.

There is an official guide at spring:
http://spring.io/guides/gs/convert-jar-to-war-maven/
Pay attention to "Initialize the servlet" section.
It explains an important point of adding a class that substitutes web.xml. Without it (or without proper web.xml) you will get a war file but when deployed nothing will be accessible in browser as nothing will be registered as your request dispatcher.
Also note that it is best to run this example on Tomcat 8 as it supports latest servlet specs. I have spent number of hours trying to figure out why it does not work on my Tomcat 7.

Related

Invalid web-app-versionType after Spring Upgrade

To support JUnit 5, I recently upgraded a Spring Boot application to version 2.4.7.
Local development uses an embedded Tomcat server, while all other environments run on a Weblogic server 12.1.3.
Everything runs locally, but using the Weblogic Server results in the following exception:
Caused By: weblogic.descriptor.DescriptorException: VALIDATION PROBLEMS WERE FOUND
/weblogic.utils.classloaders.GenericClassLoader#700d06bb finder: weblogic.utils.classloaders.CodeGenClassFinder#40ce7cdd annotation: APP#/WEB-INF/lib/tomcat-embed-websocket-9.0.46.jar!/META-INF/web-fragment.xml:18:3:18:3: problem: cvc-enumeration-valid: string value '4.0' is not a valid enumeration value for web-app-versionType in namespace http://xmlns.jcp.org/xml/ns/javaee
at weblogic.descriptor.internal.MarshallerFactory$1.evaluateResults(MarshallerFactory.java:249)
Other questions on the topic led me to check web.xml, but it contains version="3.0".
I don't know how to proceed because I don't understand where this comes from.
Do you have this in your pom.xml to exclude packaging of the tomcat jar files when creating the war file?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
The spring-boot-starter-tomcat dependencies must have provided scope.

spring-boot-starter-parent: Can this be included as dependency

I was understanding something in spring boot and to being with, used a very simple snippet, like adding this in pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
As I understand <parent> in this context means that in my pom.xml, there we have a parent pom.xml (saw the pom.xml file for spring-boot-starter-parent) which will have list of dependencies.
The important thing is that it is only pom packaging, and NOT a real jar / binary (please correct if I am wrong)
I saw the following in mvn repository:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
</dependency>
My doubt is:
How can we include it as an dependency , it is just a pom packaging (and not a real jar / war), which acts as central place which holds common dependencies? Is it allowed? I tried adding in my project, but saw errors in STS IDE.
How does this get downloaded? Can we see the contents of this "parent"
First off, you've probably missed the meaning of parent pom in this case.
Spring boot of any specific version (2.2.1 in this case) comes with a bunch of possible integrations with many technologies / libraries. So it provides "default" versions of the libraries to work with because its very hard to check that it compatible with all possible versions of all libraries. You can of course provide your own version but then you should test a compatibility as an application maintainer.
So If you'll checkout the source code of spring-boot-starter-parent pom, you'll see that it provides some plugins and plugin management and more importantly inherits from another pom called spring-boot-dependencies
Note it doesn't add any dependencies to your project. It only defines a dependencyManagement section. This means that once you'll use the dependency in your project (that inherits) from this pom, you don't have to specify a version, only group id and artifact id.
Again, that's because spring boot offers by default very specific versions of thirdparties - the version that it was verified that it's compatible with...
Now as for the second part of the question - indeed it doesn't make sense to include dependency with packaging pom like you've posted, could you please provide a link where exactly you've seen this?
Sometimes when people adopt spring boot in their projects they already have have some parent, so they can't use the inheritance, in this case they can use a very special maven scope "import" and use the dependency on pom treating it as BOM (bill of materials) - frankly a pretty advanced stuff in maven. But spring boot uses this feature for these cases.
The dependency inclusion looks like this:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
Note, the `import line. From maven's site: This is meant to allow dependency management information such as versions and excludes be retrieved from a remote POM file.
Here is a tutorial about this topic
#CuriousMind, including the spring-boot-starter-parent as a dependency is like trying to instantiate an interface or Abstract Class in Java. As you noticed, its packaging is pom, meaning it is just a maven artifact to help configure your maven project. Jar and War will contain some java binaries. I think the MVN repository code automatically generate all sample as dependencies..

Dependency listed in pom file not found in deployed project

I asked a question here that I think I may have found the root of. I have a Spring Boot app using a datasource, net.sourceforge.jtds.jdbc.Driver, that is supposed to be included transitively by Spring Boot 2.0.2 with spring-boot-starter-jpa. However, when I run
jar tf my.jar | grep jtds
the driver class isn't found (we don't have a maven executable on the server to list the classpath). Everything I do to inspect the classpath reflects that the jar isn't there.
I've done this in 2 scenarios: 1) When I didn't explicitly add the jar to my pom, I got the error reported in my previous post. 2) When I do add it explicitly to the pom, I get this error:
java.lang.IllegalStateException: Cannot load driver class: net.sourceforge.jtds.jdbc.Driver
Can someone tell me what's going on?? I am confounded as to why this class can't be found and loaded.
Please mind, that in the Spring Boot Parent POM the jtds dependency is only included in test scope.
If you want to use classes of this dependency also in your production code, please change the Maven scope to compile.
Ok, the problem was solved by adding the dependency with a runtime scope.
In child pom where jar is packaged, you should have
spring-boot-maven-plugin. and dependency as below:
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
</dependency>
In parent pom :
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>${jtds.version}</version>
</dependency>

spring boot fails to run - IllegalAccessError on startup

I have a strange issue and that I have not been able to resolve. I am trying to use the sample JPA sprint boot (v0.5.0-M6) project as a starting point for an application I am writing. I grabbed the JPA sample and got that to run locally. I then proceeded to add my code into that project. I imported into eclipse and run as spring-boot. Then I get this error:
Exception in thread "main" java.lang.IllegalAccessError: tried to access class org.springframework.core.io.DefaultResourceLoader$ClassPathContextResource from class org.springframework.boot.context.embedded.EmbeddedWebApplicationContext
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getResourceByPath(EmbeddedWebApplicationContext.java:386)
at org.springframework.core.io.DefaultResourceLoader.getResource(DefaultResourceLoader.java:100)
at org.springframework.context.support.GenericApplicationContext.getResource(GenericApplicationContext.java:211)
at org.springframework.boot.context.initializer.ConfigFileApplicationContextInitializer.load(ConfigFileApplicationContextInitializer.java:192)
at org.springframework.boot.context.initializer.ConfigFileApplicationContextInitializer.load(ConfigFileApplicationContextInitializer.java:134)
at org.springframework.boot.context.initializer.ConfigFileApplicationContextInitializer.initialize(ConfigFileApplicationContextInitializer.java:121)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:403)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:287)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:749)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:738)
From what I can tell, this is the wrong application context, since I am not using XML configuration but annotations to drive the configuration. Spring boot is automatically selecting this one and I need to tell it not to use the above. At least that is what I think I need to do.
I did search here and in the spring.io forums but no one seems to have the same issue.
Question: What drives the selection of an application context with the auto configuration?
What should I be looking at to resolve the above issue? What else do I need to provide to here help debug the auto configuration issue?
TIA,
Scott
I got the same problem.
if you use maven check your pom.xml
remove conflict version in Spring Lib.
<properties>
<hibernate.version>4.2.0.Final</hibernate.version>
<mysql.connector.version>5.1.21</mysql.connector.version>
<spring.version>3.2.2.RELEASE</spring.version>
</properties>
i remove this line
<spring.version>3.2.2.RELEASE</spring.version>
and in maven dependency just
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
Hope this help.
I was facing the same problem, and solved fixing the referencing to the boot-starter-parent pom.
At the pom.xml file I used:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>0.5.0.M6</version>
</parent>
I have some urgent issues to fix now, so I didn't inspected this parent pom to see what's so important here, but I hope this can help you - don't forget to verify the version you're using!

java.lang.ClassNotFoundException: javax.faces.webapp.FacesServlet, tomcat doesn't see javaee-api-7.0-b83.jar

I am trying to run sample guessnumber-jsf from Java EE tutorial. It is here: https://svn.java.net/svn/javaeetutorial~svn
There is no dependencies in pom.xml. So output file has no .jar file. When I try to put javaee-api-7.0-b83.jar inside tomcat/lib or WEB-INF/lib/javaee-api-7.0-b83.jar, nothing changes.
When I try to open
localhost:8080/guessnumber-jsf/faces/greeting.xhtml
I get ClassNotFoundException. Where can I get list of jars that I need for faces tutorial? How can I connect them?
You can't put that Java EE jar in Tomcat and expect it to magically morph into a Java EE server.
That particular jar only contains the APIs to link against (eg "headers" in C/C++ terminology). It does not contain any implementation.
The easiest thing to do is to dish Tomcat and download TomEE instead. Optionally download GlassFish.
These will all already contain all the functionality you need and nothing will have to be put into WEB-INF/lib. (if using Maven put the Java EE 6 GAV as a dependency with scope provided in your pom).
If you are using a Maven project you can fix this error by adding the following dependency:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.2.7</version>
</dependency>
Adding to the answer of Mike Braun, the Java EE 6 GAV for the web profile is:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6</version>
<scope>provided</scope>
</dependency>
Specifically note the scope: "provided". This means your Maven project will link against this, but it expects your runtime to have the implementations. For TomEE, GlassFish, JBoss AS 7.x, etc this is indeed the case.
In your classpath (.classpath) make sure you have entry like
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>

Resources