Use WAR Deployment with Spring Boot
This document outlines how to adjust a Spring Boot project to use WAR deployment (also known as traditional deployment). The traditional deployment of Spring helps overcome exceptions related to the SAP JCo library.
Modern and Traditional Spring Deployment
Traditionally, Java projects based on Spring were built as war files which had to be deployed to standalone application servers, such as Tomcat. With the rise of Spring Boot, the target file type changed to jar files where the application server is already built in. The advantage of that modern deployment form is that the application can be started directly without the need to administer a complex application server.
Target Projects of This Guide
This guide is applicable to all Spring-based Java projects which use the modern deployment of Spring as jar file. That comprises in the first place any project using the new CAP stack as well as the Spring Boot Maven archetype of the SAP Cloud SDK.
The problem with the modern deployment is that the SAP Java Connector library cannot be used when the application gets deployed as jar file.
That results in runtime exceptions like java.lang.NoClassDefFoundError: com/sap/conn/jco/JCoException
.
To overcome this problem, we'll outline how to adjust your project to leverage the traditional Spring deployment instead.
Use Traditional Spring Deployment
Perform the following steps to switch your project from using the modern to the traditional Spring deployment.
Change Maven Packaging
In your pom.xml
, change the packaging setting from jar
to war
.
<!-- before: -->
<!-- <packaging>jar</packaging> -->
<!-- after: -->
<packaging>war</packaging>
pom.xml
When your project uses multiple Maven modules, you need to choose the pom.xml
that contains your application code.
For instance, in a CAP project use the pom.xml
of the srv
module.
Add Maven WAR Plugin
Add the Maven WAR plugin to the pom.xml
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<!-- use latest version here -->
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
Adjust Dependency Scopes
The WAR file will be deployed into an a Tomcat application container. Thus we no longer need to include the dependencies that are now provided by the container.
Adjust your dependency management section to contain the following entries:
<dependencyManagement>
<dependencies>
<!-- Cloud SDK + SAP Java Buildpack BOMs -->
<dependencies>
<dependency>
<groupId>com.sap.cloud.sjb.cf</groupId>
<artifactId>cf-tomee7-bom</artifactId>
<version>use-latest-version-here</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.sap.cloud.sdk</groupId>
<artifactId>sdk-bom</artifactId>
<version>use-latest-version-here</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
<!-- Work around error in Buildpack BOM -->
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>stax2-api</artifactId>
<scope>compile</scope>
</dependency>
<!-- Set Spring Boot Tomcat dependencies to provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- Any further dependency management you might use
e.g. org.springframework.boot:spring-boot-dependencies -->
</dependencies>
</dependencyManagement>
Please note that the ordering of entries under the <dependencyManagement>
matters.
To ensure the correct scopes are set make sure the order is implemented as shown above.
In particular the cf-tomee7-bom
should be the first entry if possible.
- The versions for
stax2-api
andspring-boot-starter-tomcat
are not relevant, only the scopes matter
You can find more guidance on how to manage dependencies around the SAP Java Buildpack in our dedicated guide here.
Let Application Class Inherit from SpringBootServletInitializer
Make your application class a subclass of the class SpringBootServletInitializer
.
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Change the Deployment Configuration
Go to your deployment descriptor, for instance to your mta.yaml, and locate the module that contains your application under modules
.
For that particular module, perform the following changes:
- Change the
type
fromjava
tojava.tomcat
. - Change the
build-result
so that the file extension iswar
. - If not present, add the property
USE_JCO
with the valuetrue
underproperties
. - If not present, add
buildpack: sap_java_buildpack_jakarta
underparameters
.
In the following example we have commented the old values for your reference:
modules:
- name: example-project-srv
#type: java
type: java.tomcat
path: srv
properties:
SPRING_PROFILES_ACTIVE: cloud
# make sure that the property USE_JCO is present
USE_JCO: true
build-parameters:
builder: custom
commands:
- mvn clean package
# set the WAR file according to your artifact id
build-result: target/example-project.war # do not use the -exec.war variant
parameters:
buildpack: sap_java_buildpack_jakarta
provides:
- name: srv-api
properties:
srv-url: ${default-url}
requires:
- name: my-destination
Build and Deploy the Project
The presented changes do not lead to any changes in the build and deployment process. Hence, you can build and deploy your Java project as usually.
From now on, the JCo classes should be found during runtime.