diff --git a/docs/container-dist_zip.md b/docs/container-dist_zip.md
index aadd126a96..25814fba0c 100644
--- a/docs/container-dist_zip.md
+++ b/docs/container-dist_zip.md
@@ -16,7 +16,7 @@ The Dist Zip Container allows applications packaged in [`distZip`-style][] to be
Tags are printed to standard output by the buildpack detect script
-If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The Spring Auto-reconfiguration Framework will specify the `cloud` profile in addition to any others.
+If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The [Java CfEnv](framework-java-cfenv.md) framework — the replacement for the deprecated Spring Auto-reconfiguration — activates the `cloud` profile at runtime; you can also add it explicitly with `SPRING_PROFILES_INCLUDE=cloud`.
## Configuration
For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
diff --git a/docs/container-java_main.md b/docs/container-java_main.md
index fa0a943461..2061c3d03a 100644
--- a/docs/container-java_main.md
+++ b/docs/container-java_main.md
@@ -19,7 +19,7 @@ Command line arguments may optionally be configured.
Tags are printed to standard output by the buildpack detect script
-If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The Spring Auto-reconfiguration Framework will specify the `cloud` profile in addition to any others.
+If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The [Java CfEnv](framework-java-cfenv.md) framework — the replacement for the deprecated Spring Auto-reconfiguration — activates the `cloud` profile at runtime; you can also add it explicitly with `SPRING_PROFILES_INCLUDE=cloud`.
## Spring Boot
diff --git a/docs/container-spring_boot.md b/docs/container-spring_boot.md
index 17c8833acf..2a303b92d9 100644
--- a/docs/container-spring_boot.md
+++ b/docs/container-spring_boot.md
@@ -15,7 +15,7 @@ Tags are printed to standard output by the buildpack detect script
The container expects to run the application creating by running [`gradle distZip`][d] in an application built with the Spring Boot Gradle plugin.
-If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The Spring Auto-reconfiguration Framework will specify the `cloud` profile in addition to any others.
+If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The [Java CfEnv](framework-java-cfenv.md) framework — the replacement for the deprecated Spring Auto-reconfiguration — activates the `cloud` profile at runtime; you can also add it explicitly with `SPRING_PROFILES_INCLUDE=cloud`.
## CF Tasks
diff --git a/docs/container-spring_boot_cli.md b/docs/container-spring_boot_cli.md
index 93199f21ca..4f56c6b665 100644
--- a/docs/container-spring_boot_cli.md
+++ b/docs/container-spring_boot_cli.md
@@ -19,7 +19,7 @@ The Spring Boot CLI Container runs one or more Groovy (i.e. `*.groovy`) files us
Tags are printed to standard output by the buildpack detect script.
-If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The Spring Auto-reconfiguration Framework will specify the `cloud` profile in addition to any others.
+If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The [Java CfEnv](framework-java-cfenv.md) framework — the replacement for the deprecated Spring Auto-reconfiguration — activates the `cloud` profile at runtime; you can also add it explicitly with `SPRING_PROFILES_INCLUDE=cloud`.
## Configuration
For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
diff --git a/docs/framework-java-cfenv.md b/docs/framework-java-cfenv.md
index e9bbb31c71..0a94b27e2f 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 Cloud Foundry 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 details.
-It also sets the 'cloud' profile for Spring Boot applications, as the Spring AutoReconfiguration framework did.
+The `cloud` Spring profile is activated at runtime by java-cfenv's `CloudProfileApplicationListener`, which ships in the `java-cfenv-all` module. To ensure the profile is active — or to activate it independently of java-cfenv — set it explicitly. Use `SPRING_PROFILES_INCLUDE=cloud` to add `cloud` alongside any other active profiles, or `SPRING_PROFILES_ACTIVE=cloud` to set it as the sole active profile (this replaces any others). 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,54 @@ 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
+
+## How it works
+
+The framework is implemented in `src/java/frameworks/java_cf_env.go`:
+
+1. **Detect** — activates only when all of these hold: the framework is enabled (see [Configuration](#configuration)); a Spring Boot 3.x or 4.x marker is found (a `spring-boot-{3,4}.*.jar` under `BOOT-INF/lib`, `WEB-INF/lib`, or `lib/`, or a `Spring-Boot-Version: 3.*` / `4.*` entry in `META-INF/MANIFEST.MF`); and the application does not already bundle a `java-cfenv*.jar` (if it does, the buildpack backs off and uses the application's own copy).
+2. **Supply** — selects the java-cfenv version from the detected Spring Boot major (Spring Boot 3 → the manifest's `3.x` line, Spring Boot 4 → the `4.x` line) and installs the `java-cfenv-all` jar into the dependency directory.
+3. **Finalize** — appends the installed jar to `CLASSPATH` via a `.profile.d/java_cf_env.sh` script, so it is on the application's runtime classpath.
+4. **Runtime** — Spring Boot reads the jar's `META-INF/spring.factories`: the `EnvironmentPostProcessor`s map `VCAP_SERVICES` to Spring properties, and `CloudProfileApplicationListener` (in the `java-cfenv-all` module) activates the `cloud` profile when running in Cloud Foundry.
+
+## 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}'
+cf restage
+```
+
+The buildpack only re-reads this variable during staging, so a `cf restage` is required for the change to take effect.
+
+To re-enable, either set it back to `{enabled: true}` or remove the variable entirely:
+
+```bash
+cf unset-env JBP_CONFIG_JAVA_CF_ENV
+cf restage
+```
+
+| 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`
+
+`{enabled: false}` disables the **whole** framework — both the `VCAP_SERVICES` → Spring property mapping and the `cloud` profile activation. There is no option to disable only the `cloud` profile.
+
+For finer control, bundle a java-cfenv artifact in the application yourself. Because the buildpack backs off whenever a `java-cfenv*.jar` is already present, the app's choice wins:
+
+| App bundles | Property mapping | `cloud` profile |
+|-------------|------------------|-----------------|
+| _(nothing — buildpack injects `java-cfenv-all`)_ | yes | yes |
+| `java-cfenv-all` | yes | yes (app pins the version) |
+| `java-cfenv-boot` | yes | **no** (no `CloudProfileApplicationListener`) |
+| `java-cfenv` (core) | **no** (API only) | **no** |
+
+So an app can include `java-cfenv-boot` to keep property mapping without the `cloud` profile, or the bare `java-cfenv` core to opt out of all automatic behaviour and use the `CfEnv` API directly.
diff --git a/docs/spring-auto-reconfiguration-migration.md b/docs/spring-auto-reconfiguration-migration.md
index 734fccd4ec..52e7f4e541 100644
--- a/docs/spring-auto-reconfiguration-migration.md
+++ b/docs/spring-auto-reconfiguration-migration.md
@@ -2,6 +2,45 @@
This guide provides step-by-step instructions for migrating from the deprecated **Spring Auto-reconfiguration** framework to **java-cfenv**.
+> **Note — the `cloud` Spring profile**
+>
+> Spring Auto-reconfiguration activated a Spring profile named `cloud`. java-cfenv only
+> activates that profile if the `java-cfenv-all` module is on the classpath (it contains
+> `CloudProfileApplicationListener`); the `java-cfenv-boot` module does **not**. If your
+> application relies on the `cloud` profile — for example `application-cloud.yml` /
+> `application-cloud.properties` or `@Profile("cloud")` beans — either use `java-cfenv-all`,
+> or activate it explicitly. If the application already sets other active profiles, use
+> `SPRING_PROFILES_INCLUDE` to add `cloud` alongside them:
+>
+> ```bash
+> cf set-env SPRING_PROFILES_INCLUDE cloud # adds 'cloud' to any existing profiles
+> cf restage
+> ```
+>
+> Use `SPRING_PROFILES_ACTIVE=cloud` only if `cloud` should be the sole active profile (it
+> replaces any others).
+
+> **Note — controlling the automatic behaviour**
+>
+> When the application does not bundle java-cfenv itself, the buildpack injects `java-cfenv-all`
+> (property mapping **and** `cloud` profile). To scope this:
+> - `cf set-env JBP_CONFIG_JAVA_CF_ENV '{enabled: false}'` (+ `cf restage`) disables the
+> **whole** framework — both property mapping and the `cloud` profile. There is no
+> `cloud`-profile-only toggle.
+> - Because the buildpack backs off when the app already bundles a `java-cfenv*.jar`, bundling your
+> own artifact wins: `java-cfenv-boot` = property mapping without the `cloud` profile;
+> `java-cfenv` (core) = neither, use the `CfEnv` API directly.
+>
+> See [Java CfEnv Framework](framework-java-cfenv.md) for details.
+
+> **Note — backwards compatible with buildpack 4.x (java-buildpack 5.0.6+)**
+>
+> As of java-buildpack **5.0.6**, the buildpack injects `java-cfenv-all` by default, so the `cloud`
+> profile activation and the `VCAP_SERVICES` → Spring property mapping behave the same as under
+> java-buildpack 4.x. Apps that relied on either under 4.x keep working after upgrading — no
+> application change is required for the `cloud`/VCAP behaviour. (Buildpack 5.0.0–5.0.5 shipped the
+> bare `java-cfenv` core module, which activated neither; see #1349.)
+
---
## Table of Contents
@@ -52,8 +91,9 @@ This guide provides step-by-step instructions for migrating from the deprecated
io.pivotal.cfenv
- java-cfenv-boot
- 3.1.4
+ java-cfenv-all
+
+ 3.5.1
```
@@ -62,6 +102,7 @@ This guide provides step-by-step instructions for migrating from the deprecated
- Library reads `VCAP_SERVICES` and sets Spring Boot properties
- Spring Boot autoconfiguration uses these properties
- More transparent and Spring Boot native
+- `java-cfenv-all` bundles the property post-processors **and** the `cloud` profile listener (`CloudProfileApplicationListener`); use the lighter `java-cfenv-boot` instead only if you do not rely on the `cloud` profile
---
@@ -91,11 +132,11 @@ Check your `pom.xml` or `build.gradle`:
```xml
-
+
io.pivotal.cfenv
- java-cfenv-boot
- 3.1.4
+ java-cfenv-all
+ 3.5.1
```
@@ -104,7 +145,7 @@ Check your `pom.xml` or `build.gradle`:
```groovy
dependencies {
- implementation 'io.pivotal.cfenv:java-cfenv-boot:3.1.4'
+ implementation 'io.pivotal.cfenv:java-cfenv-all:3.5.1' // 4.0.0 for Spring Boot 4
}
```
@@ -227,7 +268,7 @@ You should see:
```
Java Buildpack v1.x.x | https://github.com/cloudfoundry/java-buildpack
-----> Supplying frameworks...
- java-cf-env=3.1.4
+ java-cf-env=3.5.1
```
---
@@ -453,16 +494,23 @@ public class CustomConfig {
### Issue: "cloud" profile not active
-**Cause**: java-cfenv only activates "cloud" profile on Cloud Foundry
-
-**Solution**: This is expected. Locally, the "cloud" profile won't be active.
+**Cause**: The `cloud` profile is activated by `CloudProfileApplicationListener`, which ships
+only in the `java-cfenv-all` module. If you migrated with the lighter `java-cfenv-boot` module
+instead, it does **not** carry that listener, so the `cloud` profile you had under Spring
+Auto-reconfiguration will not be active.
-To test cloud profile locally:
+**Solution**: Depend on `java-cfenv-all` (as shown in the steps above), or activate the profile
+explicitly. If the application already sets other active profiles, add `cloud` alongside them with
+`SPRING_PROFILES_INCLUDE`:
```bash
-java -jar myapp.jar --spring.profiles.active=cloud
+cf set-env SPRING_PROFILES_INCLUDE cloud # adds 'cloud' to any existing profiles
+cf restage
```
+Use `SPRING_PROFILES_ACTIVE=cloud` only if `cloud` should be the sole active profile (it replaces
+any others). To activate it locally: `java -jar myapp.jar --spring.profiles.active=cloud`.
+
---
## Rollback Plan
@@ -502,7 +550,7 @@ If you encounter migration issues:
## Summary Checklist
- [ ] Verify Spring Boot version (2.1+ required, 3.x recommended)
-- [ ] Add `java-cfenv-boot` dependency to `pom.xml` or `build.gradle`
+- [ ] Add `java-cfenv-all` dependency to `pom.xml` or `build.gradle` (match your Spring Boot major)
- [ ] Remove Spring Cloud Connectors dependencies (if present)
- [ ] Review and simplify custom service configurations
- [ ] Remove `JBP_CONFIG_SPRING_AUTO_RECONFIGURATION` environment variable
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..4fa238a6fe 100644
--- a/src/java/supply/supply.go
+++ b/src/java/supply/supply.go
@@ -181,5 +181,7 @@ func (s *Supplier) frameworkVersionSuffix(framework frameworks.Framework) string
return ""
}
- return fmt.Sprintf(" (%s)", dependency.Version)
+ // "manifest default" — the default version listed in manifest.yml, not necessarily what
+ // gets installed (e.g. java-cfenv resolves to a Spring-Boot-major-specific version).
+ return fmt.Sprintf(" (manifest default: %s)", dependency.Version)
}