You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Buildpack-injected java-cfenv silently fails to set spring.datasource.url (and username/password) from VCAP_SERVICES on Spring Boot 3.x and 4.x applications. Cloud profile activation works (since #1352); JDBC mapping does not.
Migration impact (v4 → v5)
Apps without java-cfenv in their pom.xml migrating from Ruby v4 to Go v5:
SB2 apps migrating to v5: auto-reconfiguration is disabled by default in Go v5. java-cfenv does not detect SB2. Cloud profile and JDBC auto-config are silently lost — no error, app falls back to whatever is in application.yml. Recovery: set JBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{enabled: true}', but these apps should upgrade to SB4.
SB3+/SB4 apps: cloud profile now works on v5 (gained via #1352). JDBC mapping was never functional on any buildpack version — see root cause below.
History
For SB2 apps, auto-reconfiguration (Spring Cloud Connectors) handled both cloud profile and JDBC auto-config. This worked because SB2's classloader had no classpath isolation.
When java-cfenv was introduced as the SB3+ replacement, it was assumed to provide the same functionality. However:
Ruby v4 shipped java-cfenv core jar (19KB, io.pivotal.cfenv:java-cfenv) — not java-cfenv-all. The core jar has no spring.factories at all — neither cloud profile nor JDBC mapping ever worked on v4 + SB3+. Additionally, java-cfenv's presence in components.yml (ordered before SpringAutoReconfiguration) blocks auto-reconfiguration from installing on SB3+ apps (return if java_cf_env_framework?), so the working SB2 mechanism is explicitly disabled.
Go v5 early shipped the same core jar — same problem.
Go v5 also changed the jar injection mechanism from v4's staging-time symlinks into BOOT-INF/lib/ (additional_libraries.link_to) to CLASSPATH env var + runtime symlink (zzz_classpath_symlinks.sh). This places jars on the system classpath, outside LaunchedClassLoader's classpath isolation.
In short: JDBC auto-config via java-cfenv has never worked on SB3+, on any buildpack version.
Root cause
The java-cfenv-all fat jar has two bugs:
Broken spring.factories — Gradle Shadow drops EnvironmentPostProcessor entries during merge. Only ApplicationListener=CloudProfileApplicationListener survives. CfDataSourceEnvironmentPostProcessor is never discovered by Spring Boot.
Bundles Spring Boot as compile scope — the 8MB fat jar includes all of Spring Boot. When loaded by LaunchedClassLoader, the same classes exist in two classloaders (system CL from fat jar + LaunchedClassLoader from BOOT-INF/lib/spring-boot-*.jar). Even if spring.factories is fixed, isAssignableFrom returns false → IllegalArgumentException: Class [CfDataSourceEnvironmentPostProcessor] is not assignable to factory type [EnvironmentPostProcessor].
Additionally, Go v5 places the jar on the system classpath via CLASSPATH env var. For SB3+, framework jars must be in BOOT-INF/lib/ to be loaded by LaunchedClassLoader, which resolves Spring Boot interfaces from its own classpath.
The java-cfenv thin jars
The java-cfenv-all fat jar bundles these three modules (plus transitive deps). Each has a distinct role:
java-cfenv (core, 19KB) — parses VCAP_SERVICES JSON into CfService objects. No Spring dependency. Foundation for the other modules.
java-cfenv-boot (29KB) — Spring Boot integration. Contains CloudProfileApplicationListener (activates cloud profile) and CfEnvironmentPostProcessor (maps service credentials to Spring properties). Has correct spring.factories registering both EnvironmentPostProcessor and ApplicationListener entries. Pulls in java-cfenv transitively.
java-cfenv-jdbc (17KB) — JDBC-specific mapping. Contains CfDataSourceEnvironmentPostProcessor which detects database URIs (postgres://, mysql://, etc.) and maps them to spring.datasource.url, spring.datasource.username, spring.datasource.password. Registered via META-INF/services/ SPI file.
The thin jars have correct spring.factories/SPI, no bundled Spring Boot (~1.5MB total vs 8MB fat jar), and work when placed in BOOT-INF/lib/.
Proven via 5 experiments
#
What
Result
1
Remove classpath.idx
Still 404
2
Copy fat jar to BOOT-INF/lib/ + classpath.idx
Jar loads (visible in /loaded-jars), still 404
3
Write correct spring.factories to BOOT-INF/classes/META-INF/
Change java_cf_env.go to copy jar into BOOT-INF/lib/ + classpath.idx at staging time — required even with fixed fat jar, because LaunchedClassLoader cannot resolve Spring Boot interfaces from the system classpath
Workaround: apps can add java-cfenv-boot and java-cfenv-jdbc as Maven/Gradle dependencies (4.0.1 for SB4, 3.5.2 for SB3). java-cfenv-boot pulls in java-cfenv transitively. The buildpack's hasJavaCfEnv() detects java-cfenv*.jar in BOOT-INF/lib/ and skips injection.
Affects
java-cfenv-all 3.5.2 and 4.0.1
All SB3+/SB4 exploded jars using buildpack java-cfenv injection
Integration test spring_boot_test.go VCAP mapping assertions timeout waiting for spring.datasource.url value that is never set
Summary
Buildpack-injected java-cfenv silently fails to set
spring.datasource.url(andusername/password) fromVCAP_SERVICESon Spring Boot 3.x and 4.x applications. Cloud profile activation works (since #1352); JDBC mapping does not.Migration impact (v4 → v5)
Apps without java-cfenv in their pom.xml migrating from Ruby v4 to Go v5:
SB2 apps migrating to v5: auto-reconfiguration is disabled by default in Go v5. java-cfenv does not detect SB2. Cloud profile and JDBC auto-config are silently lost — no error, app falls back to whatever is in
application.yml. Recovery: setJBP_CONFIG_SPRING_AUTO_RECONFIGURATION='{enabled: true}', but these apps should upgrade to SB4.SB3+/SB4 apps: cloud profile now works on v5 (gained via #1352). JDBC mapping was never functional on any buildpack version — see root cause below.
History
For SB2 apps,
auto-reconfiguration(Spring Cloud Connectors) handled both cloud profile and JDBC auto-config. This worked because SB2's classloader had no classpath isolation.When java-cfenv was introduced as the SB3+ replacement, it was assumed to provide the same functionality. However:
Ruby v4 shipped
java-cfenvcore jar (19KB,io.pivotal.cfenv:java-cfenv) — notjava-cfenv-all. The core jar has nospring.factoriesat all — neither cloud profile nor JDBC mapping ever worked on v4 + SB3+. Additionally, java-cfenv's presence incomponents.yml(ordered beforeSpringAutoReconfiguration) blocks auto-reconfiguration from installing on SB3+ apps (return if java_cf_env_framework?), so the working SB2 mechanism is explicitly disabled.Go v5 early shipped the same core jar — same problem.
Go v5 after fix(java-cfenv): add the mirrored java-cfenv-all jar to the classpath #1352 (2026-07-09) switched to
java-cfenv-all(fat jar) — cloud profile fixed (CloudProfileApplicationListenerpresent in spring.factories), but JDBC mapping still broken due to fat jar bugs described below.Go v5 also changed the jar injection mechanism from v4's staging-time symlinks into
BOOT-INF/lib/(additional_libraries.link_to) toCLASSPATHenv var + runtime symlink (zzz_classpath_symlinks.sh). This places jars on the system classpath, outsideLaunchedClassLoader's classpath isolation.In short: JDBC auto-config via java-cfenv has never worked on SB3+, on any buildpack version.
Root cause
The
java-cfenv-allfat jar has two bugs:Broken
spring.factories— Gradle Shadow dropsEnvironmentPostProcessorentries during merge. OnlyApplicationListener=CloudProfileApplicationListenersurvives.CfDataSourceEnvironmentPostProcessoris never discovered by Spring Boot.Bundles Spring Boot as
compilescope — the 8MB fat jar includes all of Spring Boot. When loaded byLaunchedClassLoader, the same classes exist in two classloaders (system CL from fat jar +LaunchedClassLoaderfromBOOT-INF/lib/spring-boot-*.jar). Even if spring.factories is fixed,isAssignableFromreturnsfalse→IllegalArgumentException: Class [CfDataSourceEnvironmentPostProcessor] is not assignable to factory type [EnvironmentPostProcessor].Additionally, Go v5 places the jar on the system classpath via
CLASSPATHenv var. For SB3+, framework jars must be inBOOT-INF/lib/to be loaded byLaunchedClassLoader, which resolves Spring Boot interfaces from its own classpath.The java-cfenv thin jars
The
java-cfenv-allfat jar bundles these three modules (plus transitive deps). Each has a distinct role:java-cfenv(core, 19KB) — parsesVCAP_SERVICESJSON intoCfServiceobjects. No Spring dependency. Foundation for the other modules.java-cfenv-boot(29KB) — Spring Boot integration. ContainsCloudProfileApplicationListener(activatescloudprofile) andCfEnvironmentPostProcessor(maps service credentials to Spring properties). Has correctspring.factoriesregistering bothEnvironmentPostProcessorandApplicationListenerentries. Pulls injava-cfenvtransitively.java-cfenv-jdbc(17KB) — JDBC-specific mapping. ContainsCfDataSourceEnvironmentPostProcessorwhich detects database URIs (postgres://, mysql://, etc.) and maps them tospring.datasource.url,spring.datasource.username,spring.datasource.password. Registered viaMETA-INF/services/SPI file.The thin jars have correct
spring.factories/SPI, no bundled Spring Boot (~1.5MB total vs 8MB fat jar), and work when placed inBOOT-INF/lib/.Proven via 5 experiments
classpath.idxBOOT-INF/lib/+classpath.idx/loaded-jars), still 404spring.factoriestoBOOT-INF/classes/META-INF/not assignable to EnvironmentPostProcessorBOOT-INF/lib/spring.datasource.url: jdbc:postgresql://host:5432/dbnameFix plan
java-cfenv-allupstream (pivotal-cf/java-cfenv): markspring-bootasprovidedscope, fixspring.factoriesmerge in Gradle Shadow build. See java-cfenv-all fat jar: broken spring.factories + Spring Boot leaking into uber jar pivotal-cf/java-cfenv#470.java_cf_env.goto copy jar intoBOOT-INF/lib/+classpath.idxat staging time — required even with fixed fat jar, becauseLaunchedClassLoadercannot resolve Spring Boot interfaces from the system classpathWorkaround: apps can add
java-cfenv-bootandjava-cfenv-jdbcas Maven/Gradle dependencies (4.0.1 for SB4, 3.5.2 for SB3).java-cfenv-bootpulls injava-cfenvtransitively. The buildpack'shasJavaCfEnv()detectsjava-cfenv*.jarinBOOT-INF/lib/and skips injection.Affects
java-cfenv-all3.5.2 and 4.0.1spring_boot_test.goVCAP mapping assertions timeout waiting forspring.datasource.urlvalue that is never set