diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index a8cd0049c..5f5d15a11 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -67,10 +67,15 @@ jobs:
run: |
mvn -V clean install -f ci.ant --batch-mode --no-transfer-progress --errors -DtrimStackTrace=false -DskipTests
mvn -V clean install -f ci.common --batch-mode --no-transfer-progress --errors -DtrimStackTrace=false -DskipTests
+ # Run tests that require a minimum of Java 17 or later
+ - name: Run tests that require a minimum of Java 17 or later
+ if: ${{ matrix.java == '17' || matrix.java == '21' }}
+ run:
+ ./gradlew clean install check -P"test.include"="**/TestSpringBootApplication30*" -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" --stacktrace --info
# Run tests
- name: Run tests with Gradle on Ubuntu
run:
- ./gradlew clean install check -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" -P"test.exclude"="**/DevContainerTest*" --stacktrace --info
+ ./gradlew clean install check -P"test.exclude"="**/TestSpringBootApplication30*,**/DevContainerTest*" -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" --stacktrace --info
# Copy build reports and upload artifact if build failed
- name: Copy build/report/tests/test for upload
if: ${{ failure() }}
@@ -143,11 +148,16 @@ jobs:
- name: Install ci.common
working-directory: C:/ci.common
run: mvn -V clean install --batch-mode --no-transfer-progress --errors -DtrimStackTrace=false -DskipTests
+ # Run tests that require a minimum of Java 17 or later
+ - name: Run tests that require a minimum of Java 17 or later
+ if: ${{ matrix.java == '17' || matrix.java == '21' }}
+ run:
+ ./gradlew clean install check -P"test.include"="**/TestSpringBootApplication30*" -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" --stacktrace --info --no-daemon
# Run tests
- name: Run tests with Gradle on Windows
working-directory: C:/ci.gradle
# LibertyTest is excluded because test0_run hangs
- run: ./gradlew clean install check -P"test.exclude"="**/Polling*,**/LibertyTest*,**/GenerateFeaturesTest*,**/DevContainerTest*" -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" --stacktrace --info --no-daemon
+ run: ./gradlew clean install check -P"test.exclude"="**/Polling*,**/LibertyTest*,**/GenerateFeaturesTest*,**/TestSpringBootApplication30*,**/DevContainerTest*" -Druntime=${{ matrix.RUNTIME }} -DruntimeVersion="${{ matrix.RUNTIME_VERSION }}" --stacktrace --info --no-daemon
timeout-minutes: 75
# Copy build reports and upload artifact if build failed
- name: Copy build/report/tests/test for upload
diff --git a/docs/spring-boot-support.md b/docs/spring-boot-support.md
index af2000ec5..69c939372 100644
--- a/docs/spring-boot-support.md
+++ b/docs/spring-boot-support.md
@@ -18,18 +18,20 @@ The `server.xml` file provided by the `configDirectory` or `serverXmlFile` param
| Feature | Description |
| ------- | ----------- |
| springBoot-1.5 | Required to support applications with Spring Boot version 1.5.x. |
-| springBoot-2.0 | Required to support applications with Spring Boot version 2.0.x and above. |
+| springBoot-2.0 | Required to support applications with Spring Boot version 2.x. |
+| springBoot-3.0 | Required to support applications with Spring Boot version 3.x. |
The Liberty features that support the Spring Boot starters can be found [here](https://www.ibm.com/support/knowledgecenter/SSAW57_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/rwlp_springboot.html). They should be enabled in the `server.xml` along with the appropriate Spring Boot feature.
### Gradle Compatibility
-There is a known build conflict that Spring Boot Gradle plugin 1.5.x is incompatible with Gradle 5.x. As the Spring Boot 1.5.x plugin will not be updated to support Gradle 5.x, consider upgrading the Spring Boot plugin or downgrading Gradle.
+The Spring Boot Gradle plugin 3.x requires Java 17 and a minimum of Gradle 7.5. There is a known build conflict that Spring Boot Gradle plugin 1.5.x is incompatible with Gradle 5.x. As the Spring Boot 1.5.x plugin will not be updated to support Gradle 5.x, consider upgrading the Spring Boot plugin or downgrading Gradle.
| Spring Boot version | Advised Gradle version |
| ------------------- | -------------- |
-| 2.0.x | 4.x+ |
+| 3.x | 7.5+ or 8.x |
+| 2.x | 4.x+ |
| 1.5.x | 2.9 or 3.x (Although we observed compatibility up to 4.10, proceed at your own risk)|
Refer to the [current release Spring docs](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#introduction) to be advised on Gradle compatibility for the latest Spring Boot Gradle plugin.
\ No newline at end of file
diff --git a/src/main/groovy/io/openliberty/tools/gradle/LibertyTasks.groovy b/src/main/groovy/io/openliberty/tools/gradle/LibertyTasks.groovy
index 10d896d60..888122d4a 100644
--- a/src/main/groovy/io/openliberty/tools/gradle/LibertyTasks.groovy
+++ b/src/main/groovy/io/openliberty/tools/gradle/LibertyTasks.groovy
@@ -17,6 +17,7 @@ package io.openliberty.tools.gradle
import io.openliberty.tools.gradle.extensions.ServerExtension
import io.openliberty.tools.gradle.tasks.AbstractServerTask
+import io.openliberty.tools.gradle.tasks.AbstractLibertyTask
import org.gradle.api.Project
import org.gradle.api.tasks.TaskDependency
@@ -92,8 +93,9 @@ public class LibertyTasks {
}
project.deploy {
- if (AbstractServerTask.findSpringBootVersion(project) != null) {
- if (springBootVersion?.startsWith('2')) {
+ String springBootVersion = AbstractServerTask.findSpringBootVersion(project)
+ if (springBootVersion != null) {
+ if (AbstractLibertyTask.isSpringBoot2plus(springBootVersion)) {
dependsOn 'bootJar'
} else { //version 1.5.x
dependsOn 'bootRepackage'
diff --git a/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractLibertyTask.groovy b/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractLibertyTask.groovy
index ec377ae0b..d43ec2a31 100644
--- a/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractLibertyTask.groovy
+++ b/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractLibertyTask.groovy
@@ -1,5 +1,5 @@
/**
- * (C) Copyright IBM Corporation 2017, 2021.
+ * (C) Copyright IBM Corporation 2017, 2023.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,19 +78,51 @@ abstract class AbstractLibertyTask extends DefaultTask {
return version
}
+ protected static boolean isSpringBoot1(String springBootVersion) {
+ if (springBootVersion == null) {
+ return false
+ }
+ return springBootVersion.startsWith('1.')
+ }
+
+ protected static boolean isSpringBoot2plus(String springBootVersion) {
+ if (springBootVersion == null) {
+ return false
+ }
+ if (springBootVersion.contains('.')) {
+ String majorVersion = springBootVersion.substring(0,springBootVersion.indexOf('.'))
+ try {
+ int majorVersionNumber = Integer.parseInt(majorVersion)
+ return majorVersionNumber > 1
+ } catch (NumberFormatException e) {
+ }
+ }
+ return false
+ }
+
+ protected static String getLibertySpringBootFeature(String springBootVersion) {
+ if (isSpringBoot1(springBootVersion)) {
+ return "springBoot-1.5"
+ } else if (isSpringBoot2plus(springBootVersion)) {
+ String majorVersion = springBootVersion.substring(0,springBootVersion.indexOf('.'))
+ return "springBoot-"+majorVersion+".0"
+ }
+ return null
+ }
+
protected static Task findSpringBootTask(Project project, String springBootVersion) {
if (springBootVersion == null) {
return null
}
Task task
//Do not change the order of war and java
- if (springBootVersion.startsWith('2.')) {
+ if (isSpringBoot2plus(springBootVersion)) {
if (project.plugins.hasPlugin('war')) {
task = project.bootWar
} else if (project.plugins.hasPlugin('java')) {
task = project.bootJar
}
- } else if (springBootVersion.startsWith('1.')) {
+ } else if (isSpringBoot1(springBootVersion)) {
if (project.plugins.hasPlugin('war')) {
task = project.war
} else if (project.plugins.hasPlugin('java')) {
diff --git a/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractServerTask.groovy b/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractServerTask.groovy
index 0f5b4cdd8..59376f89b 100644
--- a/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractServerTask.groovy
+++ b/src/main/groovy/io/openliberty/tools/gradle/tasks/AbstractServerTask.groovy
@@ -138,10 +138,9 @@ abstract class AbstractServerTask extends AbstractLibertyTask {
}
protected determineSpringBootBuildTask() {
- if (springBootVersion ?. startsWith('2') ) {
+ if (isSpringBoot2plus(springBootVersion)) {
return project.bootJar
- }
- else if ( springBootVersion ?. startsWith('1') ) {
+ } else if (isSpringBoot1(springBootVersion)) {
return project.bootRepackage
}
}
@@ -578,7 +577,7 @@ abstract class AbstractServerTask extends AbstractLibertyTask {
}
protected String getArchiveName(Task task){
- if (springBootVersion?.startsWith('1')) {
+ if (isSpringBoot1(springBootVersion)) {
task = project.jar
}
if (server.stripVersion){
@@ -662,7 +661,7 @@ abstract class AbstractServerTask extends AbstractLibertyTask {
appList.each { Object appObj ->
Node application = new Node(null, 'application')
if (appObj instanceof Task) {
- if (springBootVersion?.startsWith('1')) {
+ if (isSpringBoot1(springBootVersion)) {
appObj = project.jar
}
application.appendNode('appsDirectory', appDir)
diff --git a/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy b/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy
index a1a2f2039..e79b8b3b0 100644
--- a/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy
+++ b/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy
@@ -165,10 +165,10 @@ class DeployTask extends AbstractServerTask {
private String getArchiveOutputPath() {
String archiveOutputPath;
- if (springBootVersion.startsWith('2.')) {
+ if (isSpringBoot2plus(springBootVersion)) {
archiveOutputPath = springBootTask.archivePath.getAbsolutePath()
}
- else if(springBootVersion.startsWith('1.')) {
+ else if(isSpringBoot1(springBootVersion)) {
archiveOutputPath = springBootTask.archivePath.getAbsolutePath()
if (project.bootRepackage.classifier != null && !project.bootRepackage.classifier.isEmpty()) {
archiveOutputPath = archiveOutputPath.substring(0, archiveOutputPath.lastIndexOf(".")) + "-" + project.bootRepackage.classifier + "." + springBootTask.getArchiveExtension().get()
@@ -214,23 +214,31 @@ class DeployTask extends AbstractServerTask {
return targetThinAppPath;
}
- private isSpringBootUtilAvailable() {
- new FileNameFinder().getFileNames(new File(getInstallDir(project), "bin").getAbsolutePath(), "springBootUtility*")
+ private boolean isUtilityAvailable(File installDirectory, String utilityName) {
+ String utilFileName = isWindows ? utilityName+".bat" : utilityName;
+ File installUtil = new File(installDirectory, "bin/"+utilFileName);
+ return installUtil.exists();
}
private installSpringBootFeatureIfNeeded() {
- if (isClosedLiberty() && !isSpringBootUtilAvailable()) {
+ File installDir = getInstallDir(project)
+ if (!isUtilityAvailable(installDir, "springBootUtility") && isUtilityAvailable(installDir, "featureUtility")) {
String fileSuffix = isWindows ? ".bat" : ""
- File installUtil = new File(getInstallDir(project), "bin/installUtility"+fileSuffix)
-
- def installCommand = installUtil.toString() + " install springBoot-1.5 springBoot-2.0 --acceptLicense"
- def sbuff = new StringBuffer()
- def proc = installCommand.execute()
- proc.consumeProcessOutput(sbuff, sbuff)
- proc.waitFor()
- logger.info(sbuff.toString())
- if (proc.exitValue()!=0) {
- throw new GradleException("Error installing required spring boot support features.")
+ File installUtil = new File(installDir, "bin/featureUtility"+fileSuffix)
+
+ // only install springBoot feature that matches required version
+ String sbFeature = getLibertySpringBootFeature(springBootVersion)
+ if (sbFeature != null) {
+ logger.info("Required springBootUtility not found in Liberty installation. Installing feature "+sbFeature+" to enable it.");
+ def installCommand = installUtil.toString() + " installFeature " + sbFeature + " --acceptLicense"
+ def sbuff = new StringBuffer()
+ def proc = installCommand.execute()
+ proc.consumeProcessOutput(sbuff, sbuff)
+ proc.waitFor()
+ if (proc.exitValue()!=0) {
+ logger.error(sbuff.toString())
+ throw new GradleException("Error installing required spring boot support feature: "+sbFeature)
+ }
}
}
}
diff --git a/src/test/groovy/io/openliberty/tools/gradle/TestSpringBootApplication30.groovy b/src/test/groovy/io/openliberty/tools/gradle/TestSpringBootApplication30.groovy
new file mode 100644
index 000000000..4006d68df
--- /dev/null
+++ b/src/test/groovy/io/openliberty/tools/gradle/TestSpringBootApplication30.groovy
@@ -0,0 +1,136 @@
+/*
+ * (C) Copyright IBM Corporation 2023.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.openliberty.tools.gradle
+
+import groovy.xml.QName
+import org.junit.*
+import org.junit.rules.TestName
+
+public class TestSpringBootApplication30 extends AbstractIntegrationTest{
+ static File resourceDir = new File("build/resources/test/sample.springboot3")
+ static String buildFilename = "springboot_3_archive.gradle"
+
+ File buildDir;
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Before
+ public void setup() {
+ buildDir = new File(integTestDir, "/" + testName.getMethodName())
+ createDir(buildDir)
+ createTestProject(buildDir, resourceDir, testName.getMethodName() + '.gradle')
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ runTasks(buildDir,'libertyStop')
+ }
+
+
+ @Test
+ public void test_spring_boot_apps_30() {
+ try {
+ runTasks(buildDir, 'deploy', 'libertyStart')
+
+ String webPage = new URL("http://localhost:9080").getText()
+ Assert.assertEquals("Did not get expected http response.","Hello!", webPage)
+ Assert.assertTrue('defaultServer/dropins has app deployed',
+ new File(buildDir, 'build/wlp/usr/servers/defaultServer/dropins').list().size() == 0)
+ Assert.assertTrue('no app in apps folder',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps/thin-${testName.getMethodName()}-1.0-SNAPSHOT.jar").exists() )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+
+ @Test
+ public void test_spring_boot_classifier_apps_30() {
+ try {
+ runTasks(buildDir, 'deploy', 'libertyStart')
+
+ String webPage = new URL("http://localhost:9080").getText()
+ Assert.assertEquals("Did not get expected http response.","Hello!", webPage)
+ Assert.assertTrue('defaultServer/dropins has app deployed',
+ new File(buildDir, 'build/wlp/usr/servers/defaultServer/dropins').list().size() == 0)
+ Assert.assertTrue('no app in apps folder',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps/thin-${testName.getMethodName()}-1.0-SNAPSHOT-test.jar").exists() )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+
+ @Test
+ public void test_spring_boot_classifier_apps_30_no_feature() {
+ try {
+ runTasks(buildDir, 'deploy')
+
+ Assert.assertTrue('defaultServer/dropins has app deployed',
+ new File(buildDir, 'build/wlp/usr/servers/defaultServer/dropins').list().size() == 0)
+ Assert.assertTrue('no app in apps folder',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps/thin-${testName.getMethodName()}-1.0-SNAPSHOT-test.jar").exists() )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+
+ @Test
+ public void test_spring_boot_war_apps_30() {
+ try {
+ runTasks(buildDir, 'deploy', 'libertyStart')
+
+ String webPage = new URL("http://localhost:9080").getText()
+ Assert.assertEquals("Did not get expected http response.","Hello!", webPage)
+ Assert.assertTrue('defaultServer/dropins has app deployed',
+ new File(buildDir, 'build/wlp/usr/servers/defaultServer/dropins').list().size() == 0)
+ Assert.assertTrue('no app in apps folder',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps/thin-${testName.getMethodName()}-1.0-SNAPSHOT.war").exists() )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+
+ @Test
+ public void test_spring_boot_war_classifier_apps_30() {
+ try {
+ runTasks(buildDir, 'deploy', 'libertyStart')
+
+ String webPage = new URL("http://localhost:9080").getText()
+ Assert.assertEquals("Did not get expected http response.","Hello!", webPage)
+ Assert.assertTrue('defaultServer/dropins has app deployed',
+ new File(buildDir, 'build/wlp/usr/servers/defaultServer/dropins').list().size() == 0)
+ Assert.assertTrue('no app in apps folder',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps/thin-${testName.getMethodName()}-1.0-SNAPSHOT-test.war").exists() )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+
+ @Test
+ public void test_spring_boot_dropins_30() {
+ try {
+ runTasks(buildDir, 'deploy', 'libertyStart')
+ String webPage = new URL("http://localhost:9080").getText()
+ Assert.assertEquals("Did not get expected http response.","Hello!", webPage)
+ Assert.assertTrue('defaultServer/dropins/spring has no app',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/dropins/spring/thin-${testName.getMethodName()}-1.0-SNAPSHOT.jar").exists())
+ Assert.assertTrue('apps folder should be empty',
+ new File(buildDir, "build/wlp/usr/servers/defaultServer/apps").list().size() == 0 )
+ } catch (Exception e) {
+ throw new AssertionError ("Fail on task deploy.", e)
+ }
+ }
+}
diff --git a/src/test/resources/sample.springboot3/settings.gradle b/src/test/resources/sample.springboot3/settings.gradle
new file mode 100644
index 000000000..c2d3edc19
--- /dev/null
+++ b/src/test/resources/sample.springboot3/settings.gradle
@@ -0,0 +1 @@
+//Empty
\ No newline at end of file
diff --git a/src/test/resources/sample.springboot3/src/main/java/com/ibm/test/springboot/App.java b/src/test/resources/sample.springboot3/src/main/java/com/ibm/test/springboot/App.java
new file mode 100644
index 000000000..e7688517a
--- /dev/null
+++ b/src/test/resources/sample.springboot3/src/main/java/com/ibm/test/springboot/App.java
@@ -0,0 +1,18 @@
+package com.ibm.test.springboot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@RestController
+public class App {
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+ @RequestMapping("/")
+ public String index() {
+ return "Hello!";
+ }
+}
diff --git a/src/test/resources/sample.springboot3/src/main/liberty/alternateConfig/server30.xml b/src/test/resources/sample.springboot3/src/main/liberty/alternateConfig/server30.xml
new file mode 100644
index 000000000..9c1fd6140
--- /dev/null
+++ b/src/test/resources/sample.springboot3/src/main/liberty/alternateConfig/server30.xml
@@ -0,0 +1,13 @@
+
+
+
+ servlet-6.0
+
+
+
+
+
+
+
diff --git a/src/test/resources/sample.springboot3/src/main/liberty/config/server30.xml b/src/test/resources/sample.springboot3/src/main/liberty/config/server30.xml
new file mode 100644
index 000000000..a9f10f6b5
--- /dev/null
+++ b/src/test/resources/sample.springboot3/src/main/liberty/config/server30.xml
@@ -0,0 +1,14 @@
+
+
+
+ springBoot-3.0
+ servlet-6.0
+
+
+
+
+
+
+
diff --git a/src/test/resources/sample.springboot3/src/main/resources/application.properties b/src/test/resources/sample.springboot3/src/main/resources/application.properties
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_apps_30.gradle b/src/test/resources/sample.springboot3/test_spring_boot_apps_30.gradle
new file mode 100644
index 000000000..c2c1b537f
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_apps_30.gradle
@@ -0,0 +1,39 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'io.openliberty', name: 'openliberty-runtime', version: '23.0.0.10'
+}
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/config/server30.xml")
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30.gradle b/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30.gradle
new file mode 100644
index 000000000..569db154b
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30.gradle
@@ -0,0 +1,43 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'com.ibm.websphere.appserver.runtime', name: 'wlp-jakartaee10', version: '23.0.0.10'
+}
+
+bootJar {
+ archiveClassifier = 'test'
+}
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/config/server30.xml")
+ }
+}
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30_no_feature.gradle b/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30_no_feature.gradle
new file mode 100644
index 000000000..40801aba5
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_classifier_apps_30_no_feature.gradle
@@ -0,0 +1,43 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'com.ibm.websphere.appserver.runtime', name: 'wlp-jakartaee10', version: '23.0.0.10'
+}
+
+bootJar {
+ archiveClassifier = 'test'
+}
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/alternateConfig/server30.xml")
+ }
+}
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_dropins_30.gradle b/src/test/resources/sample.springboot3/test_spring_boot_dropins_30.gradle
new file mode 100644
index 000000000..bac019e86
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_dropins_30.gradle
@@ -0,0 +1,48 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'com.ibm.websphere.appserver.runtime', name: 'wlp-jakartaee10', version: '23.0.0.10'
+}
+
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/config/server30.xml")
+ //install.useOpenLiberty = false
+ looseApplication = false
+ deploy {
+ dropins = [bootJar]
+ }
+ // features {
+ // acceptLicense = true
+ // }
+ }
+}
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_war_apps_30.gradle b/src/test/resources/sample.springboot3/test_spring_boot_war_apps_30.gradle
new file mode 100644
index 000000000..2b0150509
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_war_apps_30.gradle
@@ -0,0 +1,39 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'io.openliberty', name: 'openliberty-kernel', version: '23.0.0.10'
+}
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/config/server30.xml")
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/sample.springboot3/test_spring_boot_war_classifier_apps_30.gradle b/src/test/resources/sample.springboot3/test_spring_boot_war_classifier_apps_30.gradle
new file mode 100644
index 000000000..be3382a2f
--- /dev/null
+++ b/src/test/resources/sample.springboot3/test_spring_boot_war_classifier_apps_30.gradle
@@ -0,0 +1,43 @@
+buildscript {
+ ext {
+ springBootVersion = '3.1.3'
+ }
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
+ classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion"
+ }
+}
+
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'liberty'
+
+group = 'liberty.gradle'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = 17
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
+ testImplementation('org.springframework.boot:spring-boot-starter-test')
+ libertyRuntime group: 'io.openliberty', name: 'openliberty-kernel', version: '23.0.0.10'
+}
+
+bootWar {
+ archiveClassifier = 'test'
+}
+
+liberty {
+ server {
+ serverXmlFile = file("src/main/liberty/config/server30.xml")
+ }
+}
\ No newline at end of file