diff --git a/docs/framework-java-cfenv.md b/docs/framework-java-cfenv.md
index e9bbb31c71..521b93e0fd 100644
--- a/docs/framework-java-cfenv.md
+++ b/docs/framework-java-cfenv.md
@@ -1,15 +1,22 @@
# Java CfEnv Framework
-The Java CfEnv Framework provides the `java-cfenv` library for Spring Boot 3+ applications. This library sets various Spring Boot properties by parsing CloudFoundry variables such as `VCAP_SERVICES`, allowing Spring Boot's autoconfiguration to kick in.
+The Java CfEnv Framework provides the `java-cfenv` library for Spring Boot 3.x and 4.x applications. This library sets various Spring Boot properties by parsing CloudFoundry variables such as `VCAP_SERVICES`, allowing Spring Boot's autoconfiguration to kick in.
-This is the recommended replacement for Spring AutoReconfiguration library which is deprecated. See the `java-cfenv` repostitory for more detail.
+This is the recommended replacement for Spring AutoReconfiguration library which is deprecated. See the `java-cfenv` repository for more detail.
-It also sets the 'cloud' profile for Spring Boot applications, as the Spring AutoReconfiguration framework did.
+The included `java-cfenv` library activates the `cloud` Spring profile at runtime when `VCAP_SERVICES` is present, as the Spring AutoReconfiguration framework did. The buildpack itself does not set any Spring profile.
+
+The buildpack selects the appropriate `java-cfenv` version based on the detected Spring Boot major version:
+
+| Spring Boot | java-cfenv |
+|-------------|------------|
+| 3.x | 3.x (latest) |
+| 4.x | 4.x (latest) |
| Detection Criterion |
- Existence of a `Spring-Boot-Version: 3.*` manifest entry |
- No existing `java-cfenv` library found |
+ Existence of a spring-boot-3.*.jar or spring-boot-4.*.jar in BOOT-INF/lib, WEB-INF/lib, or lib/; or a Spring-Boot-Version: 3.* / Spring-Boot-Version: 4.* entry in META-INF/MANIFEST.MF |
+ No existing java-cfenv library found in the application |
| Tags |
@@ -17,3 +24,28 @@ It also sets the 'cloud' profile for Spring Boot applications, as the Spring Aut
Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+
+The framework can be disabled via the `JBP_CONFIG_JAVA_CF_ENV` environment variable:
+
+```bash
+cf set-env JBP_CONFIG_JAVA_CF_ENV '{enabled: false}'
+```
+
+To re-enable, either set it back to `{enabled: true}` or remove the variable entirely:
+
+```bash
+cf unset-env JBP_CONFIG_JAVA_CF_ENV
+```
+
+| Variable | Default | Description |
+|----------|---------|-------------|
+| `JBP_CONFIG_JAVA_CF_ENV` | `{enabled: true}` | Enable or disable the framework |
+
+Note: if `java-cfenv*.jar` is already present in the application, the buildpack skips injection automatically — no need to disable explicitly for that case.
+
+Disable when:
+- The application handles `VCAP_SERVICES` manually with custom binding logic
+- The automatic `cloud` profile activation is unwanted
+- Another service binding library conflicts with `java-cfenv`
\ No newline at end of file
diff --git a/src/java/frameworks/java_cf_env.go b/src/java/frameworks/java_cf_env.go
index 48bf3f91f2..7a70e04cec 100644
--- a/src/java/frameworks/java_cf_env.go
+++ b/src/java/frameworks/java_cf_env.go
@@ -71,7 +71,6 @@ func (j *JavaCfEnvFramework) Supply() error {
} else {
j.context.Log.Debug("Resolved Java CF Env version pattern '%s' to %s", versionPattern, resolvedVersion)
}
-
// Install java-cfenv JAR
javaCfEnvDir := filepath.Join(j.context.Stager.DepDir(), "java_cf_env")
if err := j.context.Installer.InstallDependency(dep, javaCfEnvDir); err != nil {
diff --git a/src/java/frameworks/java_cf_env_test.go b/src/java/frameworks/java_cf_env_test.go
index b307be606f..b10f305699 100644
--- a/src/java/frameworks/java_cf_env_test.go
+++ b/src/java/frameworks/java_cf_env_test.go
@@ -68,10 +68,23 @@ var _ = Describe("Java CF Env", func() {
})
})
- Context("with Spring Boot 3.x JAR in lib/", func() {
+ Context("with Spring Boot 4.1.x JAR in BOOT-INF/lib", func() {
+ BeforeEach(func() {
+ Expect(os.MkdirAll(filepath.Join(buildDir, "BOOT-INF", "lib"), 0755)).To(Succeed())
+ Expect(os.WriteFile(filepath.Join(buildDir, "BOOT-INF", "lib", "spring-boot-4.1.0.jar"), []byte("fake"), 0644)).To(Succeed())
+ })
+
+ It("returns 'Java CF Env'", func() {
+ name, err := fw.Detect()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(name).To(Equal("Java CF Env"))
+ })
+ })
+
+ Context("with Spring Boot 4.1.x JAR in lib/", func() {
BeforeEach(func() {
Expect(os.MkdirAll(filepath.Join(buildDir, "lib"), 0755)).To(Succeed())
- Expect(os.WriteFile(filepath.Join(buildDir, "lib", "spring-boot-3.1.5.jar"), []byte("fake"), 0644)).To(Succeed())
+ Expect(os.WriteFile(filepath.Join(buildDir, "lib", "spring-boot-4.1.0.jar"), []byte("fake"), 0644)).To(Succeed())
})
It("returns 'Java CF Env'", func() {
@@ -81,10 +94,10 @@ var _ = Describe("Java CF Env", func() {
})
})
- Context("with Spring Boot 3.x JAR in WEB-INF/lib", func() {
+ Context("with Spring Boot 4.1.x JAR in WEB-INF/lib", func() {
BeforeEach(func() {
Expect(os.MkdirAll(filepath.Join(buildDir, "WEB-INF", "lib"), 0755)).To(Succeed())
- Expect(os.WriteFile(filepath.Join(buildDir, "WEB-INF", "lib", "spring-boot-3.0.0.jar"), []byte("fake"), 0644)).To(Succeed())
+ Expect(os.WriteFile(filepath.Join(buildDir, "WEB-INF", "lib", "spring-boot-4.1.0.jar"), []byte("fake"), 0644)).To(Succeed())
})
It("returns 'Java CF Env'", func() {
@@ -94,12 +107,12 @@ var _ = Describe("Java CF Env", func() {
})
})
- Context("with Spring-Boot-Version: 3.x in META-INF/MANIFEST.MF", func() {
+ Context("with Spring-Boot-Version: 4.1.x in META-INF/MANIFEST.MF", func() {
BeforeEach(func() {
Expect(os.MkdirAll(filepath.Join(buildDir, "META-INF"), 0755)).To(Succeed())
Expect(os.WriteFile(
filepath.Join(buildDir, "META-INF", "MANIFEST.MF"),
- []byte("Manifest-Version: 1.0\nSpring-Boot-Version: 3.2.0\nMain-Class: org.springframework.boot.loader.JarLauncher\n"),
+ []byte("Manifest-Version: 1.0\nSpring-Boot-Version: 4.1.0\nMain-Class: org.springframework.boot.loader.JarLauncher\n"),
0644,
)).To(Succeed())
})
@@ -206,6 +219,12 @@ var _ = Describe("Java CF Env", func() {
})
})
+ Describe("DependencyIdentifier", func() {
+ It("returns java-cfenv so supply.go can look up the manifest default version", func() {
+ Expect(fw.DependencyIdentifier()).To(Equal("java-cfenv"))
+ })
+ })
+
Describe("Finalize", func() {
Context("when the JAR is present", func() {
BeforeEach(func() {
diff --git a/src/java/supply/supply.go b/src/java/supply/supply.go
index afcd8d0943..bc4d156805 100644
--- a/src/java/supply/supply.go
+++ b/src/java/supply/supply.go
@@ -181,5 +181,5 @@ func (s *Supplier) frameworkVersionSuffix(framework frameworks.Framework) string
return ""
}
- return fmt.Sprintf(" (%s)", dependency.Version)
+ return fmt.Sprintf(" (default: %s)", dependency.Version)
}