Compare commits

...

353 Commits

Author SHA1 Message Date
Andy Wilkinson 4b8db9b630 Fix problems with auto-configuration architecture checks
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48216
2025-11-21 16:57:56 +00:00
Andy Wilkinson 85bbbc99ad Merge branch '3.5.x'
Closes gh-48229
2025-11-21 16:54:25 +00:00
Andy Wilkinson 01d93513c7 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48226
2025-11-21 16:47:11 +00:00
Andy Wilkinson 40453e76f0 Merge branch '3.5.x'
Closes gh-48228
2025-11-21 16:47:00 +00:00
Andy Wilkinson 7459fe0163 Merge branch '3.4.x' into 3.5.x
Closes gh-48227
2025-11-21 16:46:26 +00:00
Andy Wilkinson 859606ae13 Split architecture checks by language as well as source set
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48224
2025-11-21 16:44:54 +00:00
Andy Wilkinson fc8f9a322d Annotation Kotlin auto-config examples with @AutoConfiguration
Closes gh-48220
2025-11-21 16:44:54 +00:00
Stéphane Nicoll bd5264e28e Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48219
2025-11-21 13:02:14 +01:00
Stéphane Nicoll d4408ab9cd Merge pull request #48169 from vpavic
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* pr/48169:
  Polish "Revise "Use Liquibase for test-only migrations" section"
  Revise "Use Liquibase for test-only migrations" section

Closes gh-48169
2025-11-21 13:02:09 +01:00
Stéphane Nicoll 1650092890 Polish "Revise "Use Liquibase for test-only migrations" section"
See gh-48169
2025-11-21 12:05:42 +01:00
Vedran Pavic 7bc6ebc169 Revise "Use Liquibase for test-only migrations" section
See gh-48169

Signed-off-by: Vedran Pavic <vedran@vedranpavic.com>
2025-11-21 12:03:29 +01:00
Stéphane Nicoll 1e96c6cd02 Merge branch '3.5.x'
Closes gh-48218
2025-11-21 11:27:56 +01:00
Stéphane Nicoll 2f27912aea Merge branch '3.4.x' into 3.5.x
Closes gh-48217
2025-11-21 11:27:45 +01:00
Stéphane Nicoll 5bb8d711ce Refer to Infinispan documentation
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Rather than documenting what should be added to use Infinispan as a
cache provider, this commit adds a reference to the official
documentation.

Closes gh-48191
2025-11-21 11:23:40 +01:00
Stéphane Nicoll 977be74768 Document replacement for removed "max-retries" properties
See gh-48023
Closes gh-48206
2025-11-21 10:59:42 +01:00
Phillip Webb 0f4de3c4f4 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48212
2025-11-20 14:18:32 -08:00
Phillip Webb 39c0d17b87 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48211
2025-11-20 14:18:11 -08:00
Phillip Webb 4d94fcba9a Upgrade to Antora Spring UI v0.4.24
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48210
2025-11-20 14:17:47 -08:00
Andy Wilkinson 0884005212 Generate individual modules' javadoc without web fonts
Closes gh-48208
2025-11-20 19:57:14 +00:00
Phillip Webb 384e8b9b74 Next development version (v4.0.1-SNAPSHOT) 2025-11-20 10:38:42 -08:00
Andy Wilkinson 34879288f9 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48205
2025-11-20 14:20:03 +00:00
Andy Wilkinson 29b8e96978 Switch make-default in preparation for Spring Boot 4.0.0
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48203
2025-11-20 14:17:57 +00:00
Andy Wilkinson 88da0ddb94 Merge branch '3.5.x' 2025-11-20 14:17:00 +00:00
Andy Wilkinson 56feeaa9a0 Next development version (v3.5.9-SNAPSHOT) 2025-11-20 14:16:24 +00:00
Andy Wilkinson 3becdc7d47 Move server.error properties to spring.web.error
Closes gh-48201
2025-11-20 11:55:23 +00:00
Moritz Halbritter 2b306329ae Merge branch '3.5.x' 2025-11-20 12:27:44 +01:00
Moritz Halbritter 4f03b44e97 Merge branch '3.4.x' into 3.5.x 2025-11-20 12:27:10 +01:00
Moritz Halbritter 3d15c13270 Next development version (v3.4.13-SNAPSHOT)
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-20 12:26:35 +01:00
Stéphane Nicoll dc140dfc2e Upgrade to Spring Framework 7.0.1
Closes gh-48168
2025-11-20 10:48:40 +01:00
Andy Wilkinson 75da8b80ec Align restclient-test properties with module's name
Closes gh-48193
2025-11-20 09:20:02 +00:00
Andy Wilkinson 331e9bcbf7 Remove metadata for previously deleted property
Closes gh-48199
2025-11-20 09:15:42 +00:00
Andy Wilkinson 81ec7aeb70 Fix clashing bean name with JsonTest and Jacksons 2 and 3
Fixes gh-48198
2025-11-20 09:14:46 +00:00
Moritz Halbritter 21b27df695 Merge branch '3.5.x' 2025-11-20 10:04:14 +01:00
Moritz Halbritter 3b539aa9b4 Merge branch '3.4.x' into 3.5.x
Closes gh-48166
2025-11-20 10:03:52 +01:00
Moritz Halbritter ee70d55976 Upgrade to Spring Framework 6.2.14
Closes gh-48165
2025-11-20 09:56:38 +01:00
Phillip Webb 2685f4bf29 Change tomcat and jetty runtime modules to starters
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Change `spring-boot-tomcat-runtime` and `spring-boot-jetty-runtime`
into starter POMs and reduce the number of dependencies needed for
`spring-boot-tomcat` and `spring-boot-jetty`.

The runtime starters provide only the jars required to run the
embedded server along with the module jar itself (excluding transitive
dependencies) and `spring-boot-webserver` (excluding transitive
dependencies).

The build setup required for an executable jar is slightly different
between Maven and Gradle. For Maven, the regular module is put in the
`provided` scope. For Gradle, the regular module remains in main
configuration and the runtime jar is put in the `providedRuntime`
configuration. The reference documentation has been updated to
show how to configure things if starters are being used.

Manual testing has been performed to ensure that wars build with Maven
and Gradle work with both Tomcat and Jetty in both deployed and
`java -jar` modes.

Closes gh-48175
2025-11-19 21:59:03 -08:00
Phillip Webb 2e75008ba1 Merge branch '3.5.x'
Closes gh-48197
2025-11-19 21:58:48 -08:00
Phillip Webb f7b4a8b377 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48196
2025-11-19 21:58:36 -08:00
Phillip Webb 4a8d01d2b6 Exclude starter POMs from lib-provided when using Gradle
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Fixes gh-48195
2025-11-19 21:58:03 -08:00
Phillip Webb 97d58c21ce Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-19 10:35:08 -08:00
Phillip Webb 0bb0d5370a Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48192
2025-11-19 10:34:56 -08:00
Phillip Webb 4625534e83 Force Testcontainers Docker API version for Docker 29.0.0+ compatibility
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Add `docker-java.properties` to spring-boot-testcontainers and
`spring-boot-test` to force an API version upgrade.

Fixes gh-48104
2025-11-19 10:33:34 -08:00
Phillip Webb 058e455cd8 Merge branch '3.5.x'
Closes gh-48190
2025-11-19 09:38:25 -08:00
Phillip Webb 7891ebf8b1 Merge branch '3.4.x' into 3.5.x
Closes gh-48189
2025-11-19 09:38:12 -08:00
Phillip Webb b0f50581bc Upgrade to antora-ui-spring v0.4.21
Closes gh-48188
2025-11-19 09:37:42 -08:00
Stéphane Nicoll be063b695a Upgrade to Spring Batch 6.0.0
Closes gh-47834
2025-11-19 17:40:40 +01:00
Stéphane Nicoll d451da604b Merge branch '3.5.x' 2025-11-19 15:57:51 +01:00
Stéphane Nicoll 885a83407f Upgrade to Kafka 4.1.1
Closes gh-48185
2025-11-19 15:56:51 +01:00
Stéphane Nicoll c8f8798a7d Upgrade to Cassandra Driver 4.19.2
Closes gh-48184
2025-11-19 15:56:51 +01:00
Andy Wilkinson 7f15cc827b Upgrade to Spring RESTDocs 4.0.0
Closes gh-47831
2025-11-19 14:46:39 +00:00
Stéphane Nicoll 833b6daf98 Upgrade to Cassandra Driver 4.19.2
Closes gh-48183
2025-11-19 15:33:20 +01:00
Moritz Halbritter 3a13d07301 Merge branch '3.5.x'
Closes gh-48182
2025-11-19 15:08:19 +01:00
Moritz Halbritter 0addec6b68 Fix bug in SslMeterBinder when binding without registered bundles
Before this commit the meter registries were derived from the created
gauges. If the SslMeterBinder has been bound to a MeterRegistry without
any bundles, then no gauges are created. If a SslBundle is then
dynamically added, onBundleChange is called with the new bundle, but the
list of meter registries is empty (because we have no gauges). The
effect is that the newly registered bundle has no metrics.

Closes gh-48180
2025-11-19 15:06:09 +01:00
Moritz Halbritter 968a85156d Merge branch '3.5.x' 2025-11-19 15:04:32 +01:00
Moritz Halbritter 0b92b8177c Polish SslMeterBinderTests 2025-11-19 14:28:47 +01:00
Stéphane Nicoll 8b1e937677 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-19 07:55:29 +01:00
Stéphane Nicoll e1c790716d Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-19 07:53:11 +01:00
Stéphane Nicoll e7aeb036f0 Upgrade to Spring Integration 6.5.4
Closes gh-48040
2025-11-19 07:53:06 +01:00
Stéphane Nicoll bae83f997d Upgrade to Spring WS 5.0.0
Closes gh-47833
2025-11-19 07:52:59 +01:00
Stéphane Nicoll 9d3434e5b6 Upgrade to Spring Integration 7.0.0
Closes gh-47828
2025-11-19 07:52:59 +01:00
Stéphane Nicoll ab218f9bcd Upgrade to Spring GraphQL 2.0.0
Closes gh-47826
2025-11-19 07:52:59 +01:00
Stéphane Nicoll 1497f9379e Upgrade to Spring Integration 6.4.9
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48026
2025-11-19 07:52:40 +01:00
Phillip Webb c42364ce88 Revert "Merge pull request #46818 from BenchmarkingBuffalo"
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
This reverts commit 4730dcfef7, reversing
changes made to 024bb7278e.

See gh-46818
2025-11-18 17:24:29 -08:00
Phillip Webb d4b9786b8b Merge branch '3.5.x'
Closes gh-48177
2025-11-18 17:08:35 -08:00
Phillip Webb 4a016ec04d Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48176
2025-11-18 16:10:05 -08:00
Phillip Webb 3040dc14cd Apply system environment prefix to management context
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Update `ManagementContextFactory` so that any system environment prefix
set on the parent environment is applied to the child.

Closes gh-45858
2025-11-18 15:44:49 -08:00
Stéphane Nicoll ae4bf3e501 Disable Elasticsearch client's sniffer by default
This commit switches the auto-configuration of Elasticsearch to not
contribute a client's sniffer by default.

This matches the best practices as describe in
https://www.elastic.co/blog/elasticsearch-sniffing-best-practices-what-when-why-how

Closes gh-48155
2025-11-18 23:03:25 +01:00
Andy Wilkinson b1d78efbf3 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48174
2025-11-18 16:40:47 +00:00
Andy Wilkinson 45f4da7eef Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48173
2025-11-18 16:40:36 +00:00
Andy Wilkinson aecdff1bbd Merge pull request #48172 from dependabot[bot]
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* gh-48172:
  Bump js-yaml from 4.1.0 to 4.1.1 in /antora

Closes gh-48172
2025-11-18 16:40:23 +00:00
dependabot[bot] 7bc2fa0eab Bump js-yaml from 4.1.0 to 4.1.1 in /antora
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

See gh-48172
2025-11-18 16:40:01 +00:00
Stéphane Nicoll e67f2fb96b Merge pull request #48170 from vpavic
* pr/48170:
  Polish contribution
  Mention support for detecting AWS ECS in "Deploying to the Cloud"

Closes gh-48170
2025-11-18 16:23:04 +01:00
Stéphane Nicoll 15bf80d3ff Polish contribution
See gh-48170
2025-11-18 16:22:11 +01:00
Vedran Pavic 802dacb007 Mention support for detecting AWS ECS in "Deploying to the Cloud"
See gh-48170

Signed-off-by: Vedran Pavic <vedran@vedranpavic.com>
2025-11-18 16:08:03 +01:00
Stéphane Nicoll 44e29b654d Merge branch '3.5.x'
Closes gh-48171
2025-11-18 16:07:34 +01:00
Stéphane Nicoll bb247e82aa Merge pull request #48153 from TerryTaoYY
* pr/48153:
  Hande SSL metrics for dynamically registered bundles

Closes gh-48153
2025-11-18 16:07:26 +01:00
TerryTaoYY 8214f3c22b Hande SSL metrics for dynamically registered bundles
See gh-48153

Signed-off-by: TerryTaoYY <yueyang.tao@gmail.com>
2025-11-18 15:25:35 +01:00
Andy Wilkinson 3d8c439091 Upgrade to Gradle 9.2.1
Closes gh-48167
2025-11-18 12:29:23 +00:00
Stéphane Nicoll 82653185fd Merge branch '3.5.x' 2025-11-18 13:27:12 +01:00
Stéphane Nicoll 7a235ca89c Merge branch '3.4.x' into 3.5.x 2025-11-18 13:27:00 +01:00
Stéphane Nicoll 4848bc1a16 Start building against Spring Framework 7.0.1 snapshots
See gh-48168
2025-11-18 13:26:42 +01:00
Stéphane Nicoll 65df86566b Start building against Spring Framework 6.2.14 snapshots
See gh-48166
2025-11-18 13:25:46 +01:00
Stéphane Nicoll 2d9d48d472 Start building against Spring Framework 6.2.14 snapshots
See gh-48165
2025-11-18 13:23:12 +01:00
Stéphane Nicoll 7e9f5ebd96 Merge branch '3.5.x'
Closes gh-48163
2025-11-18 11:06:06 +01:00
Stéphane Nicoll 12d23a3abf Merge pull request #48156 from vpavic
* pr/48156:
  Polish contribution
  Revise AWS section of "Deploying to the Cloud" in reference manual

Closes gh-48156
2025-11-18 11:05:58 +01:00
Stéphane Nicoll 1d4551e460 Polish contribution
See gh-48156
2025-11-18 11:05:26 +01:00
Vedran Pavic 165942f8ab Revise AWS section of "Deploying to the Cloud" in reference manual
See gh-48156

Signed-off-by: Vedran Pavic <vedran@vedranpavic.com>
2025-11-18 11:04:00 +01:00
Moritz Halbritter 4af532b8ee Add starters for Micrometer Metrics
This commit adds spring-boot-starter-micrometer-metrics and
spring-boot-starter-micrometer-metrics-test.

It also uses the new starters in smoke tests and in other starters,
which depended on spring-boot-micrometer-metrics.

Closes gh-48161
2025-11-18 09:28:53 +01:00
Stéphane Nicoll cdc7a34b6d Merge branch '3.5.x' 2025-11-18 09:14:47 +01:00
Stéphane Nicoll 9f39b5e231 Merge branch '3.4.x' into 3.5.x 2025-11-18 09:14:37 +01:00
Stéphane Nicoll 7bfc93f3c4 Upgrade to Spring Session 4.0.0
Closes gh-48000
2025-11-18 09:13:21 +01:00
Stéphane Nicoll 7f58805c39 Upgrade to Spring Security 7.0.0
Closes gh-47832
2025-11-18 09:13:20 +01:00
Stéphane Nicoll 8340a62c6f Upgrade to Spring Kafka 4.0.0
Closes gh-47829
2025-11-18 09:13:20 +01:00
Stéphane Nicoll 5edeb2efcd Upgrade to Spring AMQP 4.0.0
Closes gh-47823
2025-11-18 09:13:20 +01:00
Stéphane Nicoll 448f688e0c Upgrade to Spring Security 6.5.7
Closes gh-48043
2025-11-18 09:12:59 +01:00
Stéphane Nicoll 69d23862b1 Upgrade to Spring Kafka 3.3.11
Closes gh-48041
2025-11-18 09:12:59 +01:00
Stéphane Nicoll e56f3add09 Upgrade to Spring Security 6.4.13
Closes gh-48029
2025-11-18 09:12:50 +01:00
Stéphane Nicoll 8f91773cbe Upgrade to Spring Kafka 3.3.11
Closes gh-48027
2025-11-18 09:12:50 +01:00
Phillip Webb 2e54aa6760 Merge branch '3.5.x'
Closes gh-48160
2025-11-17 21:00:09 -08:00
Phillip Webb c3c983f1d8 Merge branch '3.4.x' into 3.5.x
Closes gh-48159
2025-11-17 20:59:53 -08:00
Phillip Webb 7837583484 Add credentials to ivy settings to support commercial builds
Closes gh-46824
2025-11-17 20:54:34 -08:00
Phillip Webb 2bb967de14 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-17 18:12:48 -08:00
Phillip Webb 80ed778179 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-17 18:11:41 -08:00
Phillip Webb 0d0493e45e Fix SpringRepositoriesExtensionTests
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
See gh-46823
2025-11-17 18:11:32 -08:00
Phillip Webb 7a8bc93fef Merge branch '3.5.x'
Closes gh-48158
2025-11-17 13:00:26 -08:00
Phillip Webb fec4a92c8c Merge branch '3.4.x' into 3.5.x
Closes gh-48157
2025-11-17 12:59:17 -08:00
Phillip Webb 018fc57d64 Use spring.mavenRepositories in buildSrc for all build types
Refine `buildSrc` so that `spring.mavenRepositories()` are considered
for all build types (not just milestones and snapshots). We now pass
"springFrameworkVersion" to `SpringRepositorySupport.groovy` so that
repo.spring.io doesn't get added for OSS builds using release artifacts.

Closes gh-46823
2025-11-17 12:54:31 -08:00
Phillip Webb 2a9e6a2b93 Merge branch '3.5.x'
Fixes gh-48059
2025-11-17 11:39:19 -08:00
Phillip Webb 5954918c60 Merge branch '3.4.x' into 3.5.x
Fixes gh-48058
2025-11-17 11:37:46 -08:00
Andy Wilkinson 7f6c00d52a Stop throwing PortInUseException for unassignable address
Fixes gh-47618
2025-11-17 11:33:34 -08:00
Moritz Halbritter 4730dcfef7 Merge pull request #46818 from BenchmarkingBuffalo
* pr/46818:
  Polish "Fail fast with explicit error message for incompatible JDK version"
  Fail fast with explicit error message for incompatible JDK version

Closes gh-46818
2025-11-17 14:50:36 +01:00
Moritz Halbritter afc24aed1c Polish "Fail fast with explicit error message for incompatible JDK version"
See gh-46818
2025-11-17 14:50:13 +01:00
BenchmarkingBuffalo 2998e84616 Fail fast with explicit error message for incompatible JDK version
See gh-46818

Signed-off-by: BenchmarkingBuffalo <46448799+BenchmarkingBuffalo@users.noreply.github.com>
2025-11-17 14:48:22 +01:00
Stéphane Nicoll 024bb7278e Merge pull request #48145 from stevearmstrong-dev
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* pr/48145:
  Polish "Add missing HttpClientSettingsPropertyMapper tests"
  Add missing HttpClientSettingsPropertyMapper tests

Closes gh-48145
2025-11-17 09:54:11 +01:00
Stéphane Nicoll 971bd500d4 Polish "Add missing HttpClientSettingsPropertyMapper tests"
See gh-48145
2025-11-17 09:53:41 +01:00
Steve Armstrong 82fe577596 Add missing HttpClientSettingsPropertyMapper tests
See gh-48145

Signed-off-by: Steve Armstrong <stevearmstrong-dev@users.noreply.github.com>
2025-11-17 09:44:12 +01:00
Stéphane Nicoll 2e4566bd3d Polish 2025-11-17 09:42:06 +01:00
Stéphane Nicoll 992c905153 Merge branch '3.5.x' 2025-11-17 08:38:13 +01:00
Stéphane Nicoll 845a0aa82a Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
2025-11-17 08:38:03 +01:00
Stéphane Nicoll 2394f44474 Upgrade to Testcontainers 2.0.2
Closes gh-48152
2025-11-17 08:32:23 +01:00
Stéphane Nicoll a03981eb49 Upgrade to Jetty Reactive HTTPClient 4.1.4
Closes gh-48151
2025-11-17 08:32:19 +01:00
Stéphane Nicoll d9a378b8e5 Upgrade to Hibernate 7.1.8.Final
Closes gh-48150
2025-11-17 08:32:15 +01:00
Stéphane Nicoll 4623ba756c Upgrade to Spring Pulsar 1.2.12
Closes gh-48042
2025-11-17 08:31:38 +01:00
Stéphane Nicoll 87cdc13220 Upgrade to Jetty Reactive HTTPClient 4.0.13
Closes gh-48149
2025-11-17 08:31:38 +01:00
Stéphane Nicoll e1bcf6cbee Upgrade to Hibernate 6.6.36.Final
Closes gh-48148
2025-11-17 08:31:34 +01:00
Stéphane Nicoll 855d6960e3 Upgrade to Spring Pulsar 1.2.12
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48028
2025-11-17 08:31:31 +01:00
Stéphane Nicoll 1a22b1fdb7 Upgrade to Jetty Reactive HTTPClient 4.0.13
Closes gh-48147
2025-11-17 08:31:31 +01:00
Stéphane Nicoll a4edda3e58 Upgrade to Hibernate 6.6.36.Final
Closes gh-48146
2025-11-17 08:31:27 +01:00
Stéphane Nicoll c687998f56 Upgrade to Spring Pulsar 2.0.0
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
Run CodeQL Analysis / run-analysis (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Has been cancelled Details
Build and Deploy Snapshot / Trigger Docs Build (push) Has been cancelled Details
Build and Deploy Snapshot / Verify (push) Has been cancelled Details
Closes gh-47830
2025-11-15 16:15:48 +01:00
Stéphane Nicoll bc25b58c6f Remove outdated exclusions to commons-logging
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48142
2025-11-15 10:53:09 +01:00
Stéphane Nicoll a92cb952ba Merge pull request #48141 from filiphr
* pr/48141:
  Polish "Elasticsearch starter should depend on elasticsearch-java"
  Elasticsearch starter should depend on elasticsearch-java

Closes gh-48141
2025-11-15 10:50:59 +01:00
Stéphane Nicoll c6c649f644 Polish "Elasticsearch starter should depend on elasticsearch-java"
See gh-48141
2025-11-15 10:49:20 +01:00
Filip Hrisafov a2dc77ffe4 Elasticsearch starter should depend on elasticsearch-java
See gh-48141

Signed-off-by: Filip Hrisafov <filip.hrisafov@gmail.com>
2025-11-15 10:46:43 +01:00
Stéphane Nicoll 24cdad563c Merge branch '3.5.x' 2025-11-14 17:25:10 +01:00
Stéphane Nicoll f4fd75d642 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
Run CodeQL Analysis / run-analysis (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Has been cancelled Details
Build and Deploy Snapshot / Trigger Docs Build (push) Has been cancelled Details
Build and Deploy Snapshot / Verify (push) Has been cancelled Details
2025-11-14 17:25:02 +01:00
Stéphane Nicoll 30b19904ac Upgrade to Spring Data Bom 2025.1.0
Closes gh-47824
2025-11-14 17:24:56 +01:00
Stéphane Nicoll 0163388219 Upgrade to Spring Data Bom 2025.0.6
Closes gh-48039
2025-11-14 17:24:39 +01:00
Stéphane Nicoll 8f2a7d2abe Upgrade to Spring Data Bom 2024.1.12
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
Run CodeQL Analysis / run-analysis (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Has been cancelled Details
Build and Deploy Snapshot / Trigger Docs Build (push) Has been cancelled Details
Build and Deploy Snapshot / Verify (push) Has been cancelled Details
Closes gh-48024
2025-11-14 17:24:33 +01:00
Stéphane Nicoll 50ee576ab4 Merge pull request #48138 from stewue
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* pr/48138:
  Move mime-mappings.properties to spring-boot-web-server

Closes gh-48138
2025-11-14 14:55:28 +01:00
Stefan Würsten 9ccec12506 Move mime-mappings.properties to spring-boot-web-server
This commit moves mime-mapping.properties in the module that actually
uses it, rather than in the top-level spring-boot module.

See gh-48138

Signed-off-by: Stefan Würsten <stefan@wuersten.ch>
2025-11-14 14:52:54 +01:00
Andy Wilkinson 781035b409 Remove import of deleted auto-configuration class
See gh-47848
2025-11-14 11:14:36 +00:00
Andy Wilkinson 1fac16773d Upgrade to Elasticsearch Client 9.2.1
Closes gh-48137
2025-11-14 09:47:34 +00:00
Andy Wilkinson e6f6ee78da Move ReactiveElasticsearchClient auto-config to correct module
Closes gh-47848
2025-11-14 09:39:46 +00:00
Andy Wilkinson 8a52f4931b Merge branch '3.5.x'
Closes gh-48136
2025-11-14 09:10:21 +00:00
Andy Wilkinson bbedd1b5f2 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48135
2025-11-14 09:09:23 +00:00
Andy Wilkinson 79a99eead5 Merge pull request #48125 from K-jun98
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* gh-48125:
  Optimize StringBuilder initialization in CorrelationIdFormatter

Closes gh-48125
2025-11-14 09:01:24 +00:00
gobeomjun d64d60a8f0 Optimize StringBuilder initialization in CorrelationIdFormatter
Initialize StringBuilder with the expected capacity (this.blank.length())
to avoid unnecessary resizing and array copying during string construction.

The blank field already contains the exact length needed for the formatted
output, making it an ideal initial capacity. This improves performance for
correlation ID formatting, which is frequently called during logging
operations.

See gh-48125

Signed-off-by: gobeomjun <alap_u@naver.com>
2025-11-14 09:00:07 +00:00
Andy Wilkinson b65fe6520a Merge branch '3.5.x'
Closes gh-48134
2025-11-14 08:57:57 +00:00
Andy Wilkinson 8494df1809 Merge branch '3.4.x' into 3.5.x
Closes gh-48133
2025-11-14 08:57:43 +00:00
Andy Wilkinson fe07ad8e51 Merge pull request #48124 from K-jun98
* gh-48124:
  Fix typo in PortInUseException Javadoc

Closes gh-48124
2025-11-14 08:57:34 +00:00
gobeomjun c21f5da953 Fix typo in PortInUseException Javadoc
Change 'suppler' to 'supplier' in the `@param` documentation
for the throwIfPortBindingException method.

See gh-48124

Signed-off-by: gobeomjun <alap_u@naver.com>
2025-11-14 08:56:57 +00:00
Stéphane Nicoll 097184c2e4 Merge branch '3.5.x'
Closes gh-48132
2025-11-14 09:55:46 +01:00
Stéphane Nicoll a772242d57 Merge pull request #48129 from linw-bai
* pr/48129:
  Use beanClassLoader when checking excluded auto-configuration classes

Closes gh-48129
2025-11-14 09:55:31 +01:00
linw-bai 8bcab02efd Use beanClassLoader when checking excluded auto-configuration classes
When validating exclusions, prefer the selector's beanClassLoader for
ClassUtils.isPresent checks and fall back to the selector class loader
if the beanClassLoader is not set.

This makes presence checks consistent with the classloader context used
for loading auto-configuration candidates.

See gh-48129

Signed-off-by: linw-bai <107357009+linw-bai@users.noreply.github.com>
2025-11-14 09:47:45 +01:00
Stéphane Nicoll 78b79a7f73 Upgrade to Spring LDAP 4.0.0
Closes gh-47999
2025-11-14 09:46:38 +01:00
Andy Wilkinson 3a913ef480 Merge branch '3.5.x'
Closes gh-48131
2025-11-14 08:08:08 +00:00
Andy Wilkinson 2f1f964a2a Merge branch '3.4.x' into 3.5.x
Closes gh-48130
2025-11-14 08:07:51 +00:00
Andy Wilkinson afa2af1cf6 Correct docs on when setter is not needed with JavaBean binding
The two main changes are:

- A setter is no longer required when binding from a
  comma-separated list as long as the target list is mutable. The
  binder clears the list and then re-populates it.
- A setter is now required for arrays, previously the values
  coming from configuration properties where merged into an existing
  array. Now, the array is replaced.

Closes gh-43138
2025-11-14 08:07:41 +00:00
Phillip Webb 90d53b6d1b Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48128
2025-11-13 15:27:15 -08:00
Phillip Webb c90f61ce66 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48127
2025-11-13 15:25:08 -08:00
Phillip Webb 53bda71c3e Use platform when exporting buildpack images
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Update `DockerApi` and `Builder` to support export of images with a
specified platform. This prevents 'NotFound: content digest sha256:'
errors when building an amd64 image on an arm64 machine.

Fixes gh-46665
2025-11-13 15:19:26 -08:00
Andy Wilkinson 083a0a68af Polish "Add since to deprecations in config metadata JSON files"
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
This restores properties that were accidentally removed in the
changes for gh-48122.
2025-11-13 15:17:29 +00:00
Stéphane Nicoll a4ff1e51da Polish "Add since to deprecations in config metadata JSON files"
See gh-47972
See gh-47980
2025-11-13 15:45:46 +01:00
Andy Wilkinson 5281f5c6bc Merge branch '3.5.x'
The issue had already been fixed in 4.0 as part of the nullability
work. As such, this commit doesn't fix anything. It does, however,
merge forward a test and makes some stylistic changes to the code so
that it's aligned with the same code in 3.5.x and 3.4.x
2025-11-13 14:06:46 +00:00
Andy Wilkinson 91cb68bd17 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48123
2025-11-13 13:57:08 +00:00
Stéphane Nicoll 3d23261f87 Merge branch '3.5.x'
Closes gh-48122
2025-11-13 14:55:19 +01:00
Stéphane Nicoll b50a2d0168 Merge pull request #47980 from scottfrederick
* pr/47980:
  Polish "Add since to deprecations in config metadata JSON files"
  Add since to deprecations in config metadata JSON files
  Add since attribute to uses of DeprecatedConfigurationProperty

Closes gh-47980
2025-11-13 14:44:34 +01:00
Andy Wilkinson f3b0d5ac6d Correct handling of beans with null definitions when finding matches
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Fixes gh-48117
2025-11-13 13:38:52 +00:00
Stéphane Nicoll 5321e24790 Polish "Add since to deprecations in config metadata JSON files"
See gh-47980
2025-11-13 14:28:27 +01:00
Scott Frederick 78ea236e13 Add since to deprecations in config metadata JSON files
Add the `since` field to all deprecated properties in all
additional-spring-configuration-metadata.json files in the project.

Add to the CheckAdditionalSpringConfigurationMetadata build task to
ensure that all deprecated properties have a non-empty `since` field.

See gh-47980

Signed-off-by: Scott Frederick <scottyfred@gmail.com>
2025-11-13 14:28:27 +01:00
Scott Frederick e1c33a7e3a Add since attribute to uses of DeprecatedConfigurationProperty
Add an architecture rule to ensure that all usages of
`@DeprecatedConfigurationProperty` in the Spring Boot codebase include
the `since` attribute.

Add the `since` attribute to the few places where it was not already
included.

See gh-47980

Signed-off-by: Scott Frederick <scottyfred@gmail.com>
2025-11-13 14:28:27 +01:00
Stéphane Nicoll 864252d603 Merge branch '3.5.x' 2025-11-13 14:21:27 +01:00
Stéphane Nicoll 685c66ad88 Merge branch '3.4.x' into 3.5.x 2025-11-13 14:21:20 +01:00
Stéphane Nicoll 43b4b26c18 Upgrade to Spring HATEOAS 3.0.0
Closes gh-47827
2025-11-13 14:10:41 +01:00
Stéphane Nicoll 9208041dc3 Upgrade to Spring Framework 7.0.0
Closes gh-47825
2025-11-13 14:10:41 +01:00
Stéphane Nicoll eeb256bdcb Upgrade to Jetty 12.1.4
Closes gh-48120
2025-11-13 14:10:40 +01:00
Stéphane Nicoll f8d493fbd1 Upgrade to Spring Framework 6.2.13
Closes gh-48025
2025-11-13 14:06:18 +01:00
Stéphane Nicoll e39d332b3a Upgrade to Jetty 12.0.30
Closes gh-48119
2025-11-13 14:06:18 +01:00
Stéphane Nicoll 814086340f Upgrade to Spring Framework 6.2.13
Closes gh-48036
2025-11-13 14:05:07 +01:00
Stéphane Nicoll 2b40bae906 Upgrade to Jetty 12.0.30
Closes gh-48118
2025-11-13 14:05:07 +01:00
Andy Wilkinson bb0437c0e1 Correct names of isolated Json/ObjectMapper properties
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48116
2025-11-13 12:00:19 +00:00
Andy Wilkinson 62a1dd6ed1 Merge branch '3.5.x'
Closes gh-48115
2025-11-13 11:29:47 +00:00
Andy Wilkinson d9e6be9b21 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48114
2025-11-13 11:24:24 +00:00
Andy Wilkinson 59224fdd6f Document Actuator's ObjectMapper isolation
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-47039
2025-11-13 11:24:16 +00:00
Andy Wilkinson f1aae5c7fc Merge branch '3.5.x'
Closes gh-48112
2025-11-13 10:56:53 +00:00
Andy Wilkinson 4e75a07ef7 Merge branch '3.4.x' into 3.5.x
Closes gh-48111
2025-11-13 10:56:42 +00:00
Andy Wilkinson eeebc37813 Document how to configure ServletContext init parameters
Closes gh-47951
2025-11-13 10:56:18 +00:00
Andy Wilkinson 5625209aba Merge branch '3.5.x' 2025-11-13 10:44:42 +00:00
Andy Wilkinson 4f6e3e84e8 Merge branch '3.4.x' into 3.5.x 2025-11-13 10:43:36 +00:00
Andy Wilkinson b86cdd7719 Polish 2025-11-13 10:43:17 +00:00
Andy Wilkinson 9cc18130e6 Merge branch '3.5.x'
Closes gh-48110
2025-11-13 10:19:47 +00:00
Andy Wilkinson eed7f75f9e Merge branch '3.4.x' into 3.5.x
Closes gh-48107
2025-11-13 10:17:47 +00:00
Andy Wilkinson b09b0296c3 Check aggregated property metadata
Closes gh-47972
2025-11-13 10:16:38 +00:00
Stéphane Nicoll e89bb1f62f Merge branch '3.5.x'
Closes gh-48109
2025-11-13 10:56:04 +01:00
Stéphane Nicoll b543ab81f1 Merge branch '3.4.x' into 3.5.x
Closes gh-48108
2025-11-13 10:54:05 +01:00
Stéphane Nicoll fc826218b4 Merge pull request #48100 from nosan
* pr/48100:
  Use ObjectNode for building ImagePlatform JSON

Closes gh-48100
2025-11-13 10:53:55 +01:00
Dmytro Nosan d251b99615 Use ObjectNode for building ImagePlatform JSON
See gh-48100

Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>

Closes gh-48100
2025-11-13 10:53:41 +01:00
Stéphane Nicoll d1e5fe3248 Merge branch '3.5.x'
Closes gh-48106
2025-11-13 10:31:25 +01:00
Stéphane Nicoll 1ce1b7ee35 Merge branch '3.4.x' into 3.5.x
Closes gh-48105
2025-11-13 10:27:51 +01:00
Stéphane Nicoll 9e656c1554 Remove unnecessary field initialization
Closes gh-45168

Co-authored-by: CatiaCorreia catia.correia97@gmail.com
2025-11-13 10:21:05 +01:00
Phillip Webb 55c3f03144 Merge branch '3.5.x'
Closes gh-48103
2025-11-12 20:44:55 -08:00
Phillip Webb d1dc9579eb Merge branch '3.4.x' into 3.5.x
Closes gh-48102
2025-11-12 20:05:58 -08:00
Phillip Webb 9b387cbe77 Support recent Docker installs by raising the API version when possible
Update `DockerApi` so that the URL uses version `v1.50` whenever
possible. Prior to this commit, `v1.24` was often used which breaks
recent Docker installs due to the dropping of API version v1.43 and
below.

If the actual API version running is less than `v1.50`, but greater
than the minimum required for the API call, it will be used instead.
This hopefully means that older versions of Docker will continue to
work as they did previously.

Fixes gh-48050
2025-11-12 19:57:36 -08:00
Phillip Webb a25bcfc610 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48099
2025-11-12 14:22:17 -08:00
Phillip Webb 25a5d4343e Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48098
2025-11-12 13:44:02 -08:00
Phillip Webb b6460eaf67 Merge pull request #47292 from hojooo
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
* pr/47292:
  Polish 'Correctly handle platform specific buildpack builds'
  Correctly handle platform specific buildpack builds

Closes gh-47292
2025-11-12 13:27:07 -08:00
Brian Clozel d161aafcdf Restrict Kotlin serialization when alternative is available
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
This commit applies similar changes already contributed to the
`HttpMessageConverter` stack for MVC applications.
Since there was no auto-configuration for Kotlinx JSON Serialization on
the reactive side, this commit adds a relevant `CodecCustomizer` that
will use an available `Json` bean and use it to configure a codec that:

* will only consider `@Serializable`-annotated types if another JSON
  library is available
* will use a broader support with Kotlinx Serialization otherwise

Fixes gh-48070
2025-11-12 21:09:39 +01:00
Andy Wilkinson eb381d642a Provide default values for Kotlinx Serialization JSON properties
Closes gh-48097
2025-11-12 19:50:20 +00:00
Phillip Webb 39f3d1c72c Polish 'Correctly handle platform specific buildpack builds'
See gh-47292
2025-11-12 11:07:29 -08:00
hojooo 913c434b90 Correctly handle platform specific buildpack builds
Prior to this commit, performing a build on a ARM Mac with the default
configuration and then building it again with the image platform set to
`linux/amd64` results in an "Image platform mismatch detected" failure.

This is due to the fact that `docker inspect` returns JSON for the
default platform, regardless of the fact that another architecture
has been pulled.

To solve the issue, the `inspect` API call on Docker 1.49+ can now
accept a platform query parameter which when specified returns platform
specific JSON.

At the time of this commit, the Docker API documentation hasn't been
updated, despite PR https://github.com/moby/moby/pull/49586 being
merged.

In addition to using the correct inspect JSON, we also need to pin
the run image we use to a specific digest. Without doing this,
buildpacks revert back to the default platform image and
"content digest not found" errors are thrown (similar to
https://github.com/buildpacks/docs/issues/818).

See gh-47292

Signed-off-by: hojooo <ghwn5833@gmail.com>
2025-11-12 10:33:22 -08:00
Andy Wilkinson 5699915383 Rename module for Kotlinx Serialization JSON support
Closes gh-48076
2025-11-12 17:34:28 +00:00
Brian Clozel 44f0c772a2 Configure JSON and XML converters on HttpMessageConverters
This commit ensures that XML and JSON converters on both client and
server are configured using the dedicated methods on
`HttpMessageConverters`, instead of pushing them ahead of default
converters.

Closes gh-47917
Fixes gh-48096
2025-11-12 16:15:13 +01:00
Andy Wilkinson edd530c7e1 Merge branch '3.5.x'
Closes gh-48095
2025-11-12 14:56:19 +00:00
Andy Wilkinson adbeb7a03d Include in the appendix properties described using only manual metadata
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48073
2025-11-12 14:55:06 +00:00
Stéphane Nicoll 4dd933738c Upgrade to Tomcat 11.0.14
Closes gh-48094
2025-11-12 15:51:03 +01:00
Stéphane Nicoll 0cb87dd047 Upgrade to Prometheus Client 1.4.3
Closes gh-48093
2025-11-12 15:51:03 +01:00
Stéphane Nicoll 5dffa3da4e Upgrade to MySQL 9.5.0
Closes gh-48092
2025-11-12 15:51:03 +01:00
Stéphane Nicoll 9aea720fd8 Upgrade to Logback 1.5.21
Closes gh-48091
2025-11-12 15:51:03 +01:00
Stéphane Nicoll 24cc3e490f Upgrade to jOOQ 3.19.28
Closes gh-48090
2025-11-12 15:51:03 +01:00
Stéphane Nicoll d530c2c104 Upgrade to Jackson Bom 3.0.2
Closes gh-48089
2025-11-12 15:51:03 +01:00
Stéphane Nicoll 978959658b Upgrade to Hibernate 7.1.7.Final
Closes gh-48088
2025-11-12 15:51:03 +01:00
Stéphane Nicoll c7bc4ff263 Upgrade to DB2 JDBC 12.1.3.0
Closes gh-48087
2025-11-12 15:51:03 +01:00
Andy Wilkinson 8e71f9b77a Merge branch '3.5.x'
Closes gh-48082
2025-11-12 14:29:26 +00:00
Andy Wilkinson 0458fa73e1 Merge branch '3.4.x' into 3.5.x
Closes gh-48081
2025-11-12 14:28:58 +00:00
Andy Wilkinson b6d9c48cbd Upgrade to antora-ui-spring 0.4.20
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48077
2025-11-12 14:28:49 +00:00
Stéphane Nicoll 0be793ad11 Merge branch '3.5.x' 2025-11-12 15:27:56 +01:00
Stéphane Nicoll f84b1811f2 Merge branch '3.4.x' into 3.5.x 2025-11-12 15:27:50 +01:00
Stéphane Nicoll 4c0edafb0d Upgrade to Tomcat 10.1.49
Closes gh-48086
2025-11-12 15:15:04 +01:00
Stéphane Nicoll a0962920ba Upgrade to Logback 1.5.21
Closes gh-48085
2025-11-12 15:14:59 +01:00
Stéphane Nicoll 43cc205430 Upgrade to jOOQ 3.19.28
Closes gh-48084
2025-11-12 15:14:55 +01:00
Stéphane Nicoll 3ffdf4cb0d Upgrade to DB2 JDBC 12.1.3.0
Closes gh-48083
2025-11-12 15:14:51 +01:00
Stéphane Nicoll 2993a6c3ff Upgrade to Tomcat 10.1.49
Closes gh-48080
2025-11-12 15:14:06 +01:00
Stéphane Nicoll 7c36b7f01d Upgrade to Logback 1.5.21
Closes gh-48079
2025-11-12 15:14:02 +01:00
Stéphane Nicoll df21e2e24d Upgrade to jOOQ 3.19.28
Closes gh-48078
2025-11-12 15:13:58 +01:00
Stéphane Nicoll 481e92dc4b Merge branch '3.5.x'
Closes gh-48075
2025-11-12 13:39:47 +01:00
Stéphane Nicoll f64e84e8c7 Prevent upgrade to Cassandra Driver 4.19.1
Closes gh-48074
2025-11-12 13:37:09 +01:00
Stéphane Nicoll 3e0eb7d930 Merge branch '3.5.x' 2025-11-12 13:21:12 +01:00
Stéphane Nicoll c7c09588c1 Adapt assertion to relax newlines check
See gh-47984
2025-11-12 13:20:51 +01:00
Stéphane Nicoll 73087f369b Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48071
2025-11-12 13:08:31 +01:00
Stéphane Nicoll 52951ed8f4 Apply checks for manual configuration metadata
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
This commit adds a 'org.springframework.boot.configuration-metadata'
plugin to be used for projects that only define manual metadata. Such
project do not need the annotation processor, but do not to check that
the structure of the metadata content matches the same rules.

Closes gh-47984
2025-11-12 13:01:56 +01:00
Andy Wilkinson 4096b736c8 Tolerate race condition in httpRequestsAreTimed
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Tomcat 11 will [1] send a response as soon as Content-Length bytes has
been written. This initiates a race between the timer being registered
on the server side and the test receiving the response and looking for
the timer.

Rather than sleeping for a fix period of time, we now use Awaitility
to await the availability of the timer.

Closes gh-48049

[1] 69eff83577
2025-11-12 11:40:30 +00:00
Andy Wilkinson 58cdf71b52 Restrict Kotlin serialization when alternative is available
Previously, Kotlin Serialization would be used too aggressively then
an alternative JSON converter was available. This could lead to
unwanted results when a response should have been serialized using
Jackson, for example, rather than Kotlin Serialization.

This commit addresses this by only allowing Kotlin Serialization to
serialize types that are not annotated with @Serializable when no
alternative JSON converter is available.

Fixes gh-48070
2025-11-12 10:00:45 +00:00
Brian Clozel 2e52c3c35e Update Kotlin Serialization configuration in HttpMessageConverters
As of As of spring-projects/spring-framework#35733, Spring Framework has
a dedicated method for configuring a Kotlin Serialization converter
specifically.

This commit uses this method instead of configuring the Kotlin
Serialization JSON support as a custom converter. This also removes the
`@Order` on the Kotlin converter bean itself, as there is no need to
order it in the list of custom converters anymore.

Closes gh-47917
2025-11-12 09:48:55 +01:00
Andy Wilkinson fc66e12bd7 Merge branch '3.5.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48066
2025-11-11 19:01:18 +00:00
Andy Wilkinson bd2a8acc21 Merge branch '3.4.x' into 3.5.x
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:25], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48065
2025-11-11 18:59:13 +00:00
Andy Wilkinson d697fc0b35 Upgrade to Antora UI Spring v0.4.19
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run CodeQL Analysis / run-analysis (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details
Closes gh-48064
2025-11-11 18:57:12 +00:00
Andy Wilkinson 152c09d850 Merge branch '3.5.x'
Closes gh-48063
2025-11-11 18:46:59 +00:00
Andy Wilkinson bab7307606 Merge branch '3.4.x' into 3.5.x
Closes gh-48062
2025-11-11 18:44:52 +00:00
Andy Wilkinson 5aeaa74508 Document how soon-to-expire SSL certs are reported
Closes gh-45564
2025-11-11 18:44:21 +00:00
Andy Wilkinson d844840ea2 Merge branch '3.5.x' 2025-11-11 17:02:42 +00:00
Andy Wilkinson f1b26e9402 Merge branch '3.4.x' into 3.5.x
Closes gh-48061
2025-11-11 17:02:30 +00:00
Andy Wilkinson a21bfc2ff5 Delay ServletContext destruction until Undertow is destroyed
Previously, all destruction was done in the stop method including
closing any Closeables registered with the server. One of these
Closeables managed the lifecycle of the DeploymentManager for the
servlet deployment. Closing it made the servlet context unusable
in `@PreDestroy` methods and upon restart.

This commit moves the closing of the registered Closeables into
destroy(). This allows `@PreDestory` methods to use the
ServletContext. It also allows the server to be stopped and then
restarted without making the ServletContext unusable as it's left
running while the server itself is stopped and not accepting
requests.

Fixes gh-47141
2025-11-11 17:00:48 +00:00
Andy Wilkinson 93a3511f8a Revert "Merge branch '3.5.x'"
This reverts commit 001f953cc9, reversing
changes made to 0ae86935ae.

See gh-48059
2025-11-11 16:38:33 +00:00
Andy Wilkinson c7c0d33b86 Revert "Merge branch '3.4.x' into 3.5.x"
This reverts commit 4089156b3c, reversing
changes made to 049c6d50d5.

See gh-48058
2025-11-11 16:37:27 +00:00
Andy Wilkinson 8249929b68 Revert "Stop throwing PortInUseException for unassignable address"
This reverts commit 5229ac7e58.

The change works on macOS but not on Linux.

See gh-47618
2025-11-11 16:35:24 +00:00
Andy Wilkinson 001f953cc9 Merge branch '3.5.x'
Closes gh-48059
2025-11-11 16:11:27 +00:00
Andy Wilkinson 4089156b3c Merge branch '3.4.x' into 3.5.x
Closes gh-48058
2025-11-11 16:09:14 +00:00
Andy Wilkinson 5229ac7e58 Stop throwing PortInUseException for unassignable address
Previously, an unassignable address would result in NettyWebServer
incorrectly throwing a PortInUseException.

Fixes gh-47618
2025-11-11 16:07:35 +00:00
Andy Wilkinson 0ae86935ae Merge branch '3.5.x'
Closes gh-48057
2025-11-11 15:29:33 +00:00
Andy Wilkinson 049c6d50d5 Merge branch '3.4.x' into 3.5.x
Closes gh-48056
2025-11-11 15:22:52 +00:00
Andy Wilkinson d08ac5ce4a Allow cache removals to be registered as a function counter
Fixes gh-46212
2025-11-11 15:21:40 +00:00
Andy Wilkinson 756a6408fe Merge branch '3.5.x'
Closes gh-48055
2025-11-11 14:25:35 +00:00
Andy Wilkinson 5c711e2a88 Merge branch '3.4.x' into 3.5.x
Closes gh-48054
2025-11-11 14:04:54 +00:00
Andy Wilkinson 06fd384e59 Include WebSecurityCustomizer components in WebMvcTest
This commit also tests that WebSecurityConfigurer components are
included. They include was already there but the functionality was
untested.

Fixes gh-47255
2025-11-11 14:03:25 +00:00
Moritz Halbritter 93b14bf07e Upgrade to Native Build Tools Plugin 0.11.3
Closes gh-48051
2025-11-11 14:36:50 +01:00
Moritz Halbritter 72740e0f48 Merge branch '3.5.x'
Closes gh-48053
2025-11-11 14:29:39 +01:00
Moritz Halbritter f69fbdb5f5 Merge branch '3.4.x' into 3.5.x
Closes gh-48052
2025-11-11 14:15:57 +01:00
Moritz Halbritter e58c8975f6 Document how to use ContextPropagatingTaskDecorator for propagating trace context over thread boundaries
Closes gh-47893
2025-11-11 12:51:11 +01:00
Moritz Halbritter 3c64bdf118 Document that you need to build with Java 25 for buildpack build-image Graal support
Closes gh-45501
2025-11-11 12:00:19 +01:00
Andy Wilkinson bbfd9f892b Revert "Remove sleep that appears to no longer be needed"
This reverts commit 6e8481bfff.

See gh-48049
2025-11-11 10:22:08 +00:00
Stéphane Nicoll 8584f604e3 Rename maxAttempts to maxRetries
Closes gh-48023
2025-11-11 10:22:08 +00:00
Stéphane Nicoll 8bd2fb5566 Start building against Spring WS 5.0.0 snapshots
See gh-47833
2025-11-11 10:22:08 +00:00
Stéphane Nicoll d8fa17d326 Start building against Spring Session 4.0.0 snapshots
See gh-48000
2025-11-11 10:22:08 +00:00
Stéphane Nicoll 12b7edcb5e Start building against Spring Security 7.0.0 snapshots
See gh-47832
2025-11-11 10:22:08 +00:00
Stéphane Nicoll 6f62f28579 Start building against Spring RESTDocs 4.0.0 snapshots
See gh-47831
2025-11-11 10:22:07 +00:00
Stéphane Nicoll 47691b0bd3 Start building against Spring Pulsar 2.0.0 snapshots
See gh-47830
2025-11-11 10:22:07 +00:00
Stéphane Nicoll b924878f31 Start building against Spring LDAP 4.0.0 snapshots
See gh-47999
2025-11-11 10:22:07 +00:00
Stéphane Nicoll 54993db69c Start building against Spring Kafka 4.0.0 snapshots
See gh-47829
2025-11-11 10:22:07 +00:00
Stéphane Nicoll 2545798ba2 Start building against Spring Integration 7.0.0 snapshots
See gh-47828
2025-11-11 10:22:07 +00:00
Stéphane Nicoll 0165bd8ba1 Start building against Spring HATEOAS 3.0.0 snapshots
See gh-47827
2025-11-11 10:22:06 +00:00
Stéphane Nicoll 60451c04a0 Upgrade to GraphQL Java 25.0
Closes gh-48034
2025-11-11 10:22:06 +00:00
Stéphane Nicoll 20ef8de9a1 Start building against Spring GraphQL 2.0.0 snapshots
See gh-47826
2025-11-11 10:22:06 +00:00
Stéphane Nicoll 00f60da0de Start building against Spring Framework 7.0.0 snapshots
See gh-47825
2025-11-11 10:22:06 +00:00
Stéphane Nicoll 721ba65888 Upgrade to Neo4j Java Driver 6.0.2
Closes gh-47997
2025-11-11 10:22:06 +00:00
Stéphane Nicoll 0814e2eaf6 Start building against Spring Data Bom 2025.1.0 snapshots
See gh-47824
2025-11-11 10:22:05 +00:00
Stéphane Nicoll 2ff5b88903 Start building against Spring Batch 6.0.0 snapshots
See gh-47834
2025-11-11 10:22:05 +00:00
Stéphane Nicoll 3928c53740 Start building against Spring AMQP 4.0.0 snapshots
See gh-47823
2025-11-11 10:22:05 +00:00
Moritz Halbritter 995e8560f5 Clarify use of OpenTelemetry's environment variables
See gh-47960
2025-11-11 10:16:26 +01:00
Phillip Webb 6158a52b8c Support deprecated EnvironmentPostProcessor arguments
Fixes gh-48047
2025-11-10 15:51:53 -08:00
Stéphane Nicoll 86bebfbce8 Merge branch '3.5.x' 2025-11-10 21:37:51 +01:00
Stéphane Nicoll ee16ba855e Merge branch '3.4.x' into 3.5.x 2025-11-10 21:37:43 +01:00
Stéphane Nicoll 7148bce650 Start building against Spring Security 6.5.7 snapshots
See gh-48043
2025-11-10 21:37:40 +01:00
Stéphane Nicoll cc76ad8b3a Start building against Spring Pulsar 1.2.12 snapshots
See gh-48042
2025-11-10 21:37:40 +01:00
Stéphane Nicoll e784097c1b Start building against Spring Kafka 3.3.11 snapshots
See gh-48041
2025-11-10 21:37:40 +01:00
Stéphane Nicoll 510a8eba80 Start building against Spring Integration 6.5.4 snapshots
See gh-48040
2025-11-10 21:37:40 +01:00
Stéphane Nicoll 592610dc47 Upgrade to Neo4j Java Driver 5.28.10
Closes gh-48044
2025-11-10 21:37:40 +01:00
Stéphane Nicoll e8fb8c765f Start building against Spring Data Bom 2025.0.6 snapshots
See gh-48039
2025-11-10 21:37:40 +01:00
Stéphane Nicoll ad4dcc9df5 Start building against Spring Security 6.4.13 snapshots
See gh-48029
2025-11-10 21:37:30 +01:00
Stéphane Nicoll c6dd5f6e67 Start building against Spring Pulsar 1.2.12 snapshots
See gh-48028
2025-11-10 21:37:30 +01:00
Stéphane Nicoll c43203e1c5 Start building against Spring Kafka 3.3.11 snapshots
See gh-48027
2025-11-10 21:37:30 +01:00
Stéphane Nicoll 6f7530e61a Start building against Spring Integration 6.4.9 snapshots
See gh-48026
2025-11-10 21:37:30 +01:00
Stéphane Nicoll 0f9d1eacef Upgrade to Neo4j Java Driver 5.28.10
Closes gh-48030
2025-11-10 21:37:30 +01:00
Stéphane Nicoll 1763cf7a29 Start building against Spring Data Bom 2024.1.12 snapshots
See gh-48024
2025-11-10 21:37:30 +01:00
Andy Wilkinson 032f9157c5 Merge branch '3.5.x'
Closes gh-48046
2025-11-10 20:30:09 +00:00
Andy Wilkinson 07446bb918 Merge branch '3.4.x' into 3.5.x
Closes gh-48045
2025-11-10 20:29:24 +00:00
Andy Wilkinson 4287826ff0 Use mirror for Tomcat downloads
Closes gh-48038
2025-11-10 20:28:24 +00:00
Andy Wilkinson c081cdbf28 Merge branch '3.5.x' 2025-11-10 18:10:35 +00:00
Andy Wilkinson 083b390fd4 Merge branch '3.4.x' into 3.5.x
See gh-48036
Closes gh-48037
2025-11-10 18:09:10 +00:00
Andy Wilkinson ad67a77207 Start building against Spring Framework 6.2.13 snapshots
See gh-48025
Closes gh-48032
2025-11-10 17:48:05 +00:00
Stéphane Nicoll bb9d3ecdfb Merge branch '3.5.x' 2025-11-10 15:52:23 +01:00
Stéphane Nicoll 74d69d6e44 Merge branch '3.4.x' into 3.5.x
See gh-47940
2025-11-10 15:51:19 +01:00
Stéphane Nicoll 5a67f5707e Replace calls to deprecated setConnectionTimeout method
Replace calls to the recently deprecated `setConnectionTimeout` method
of `HttpComponentsClientHttpRequestFactoryBuilder`.

This commit also introduces a `withConnectionConfigCustomizer` and
allows connection timeouts settings to be used.

Closes gh-48031
2025-11-10 15:32:05 +01:00
Andy Wilkinson 0e44f1de42 Merge branch '3.5.x' 2025-11-10 10:39:32 +00:00
Moritz Halbritter 62177a1cd7 Improve documentation for Spring Boot's OpenTelemetry support
Closes gh-47960
2025-11-10 11:15:43 +01:00
Andy Wilkinson 5b960b21b4 Merge branch '3.4.x' into 3.5.x 2025-11-10 09:56:13 +00:00
Andy Wilkinson f1957a9740 Address warnings reported by Eclipse 2025-11-10 09:55:50 +00:00
Stéphane Nicoll 49d72c2d11 Merge branch '3.5.x' 2025-11-10 09:56:16 +01:00
Stéphane Nicoll 0ab3139cc7 Merge branch '3.4.x' into 3.5.x 2025-11-10 09:56:02 +01:00
Stéphane Nicoll 7defa59a9d Upgrade to Reactor Bom 2024.0.12
Closes gh-48022
2025-11-10 09:44:55 +01:00
Stéphane Nicoll fd500f9334 Upgrade to R2DBC Postgresql 1.0.9.RELEASE
Closes gh-48021
2025-11-10 09:44:51 +01:00
Stéphane Nicoll 7c8eac6d5b Upgrade to MySQL 9.5.0
Closes gh-48020
2025-11-10 09:44:47 +01:00
Stéphane Nicoll 65cdf907f4 Upgrade to Micrometer Tracing 1.4.12
Closes gh-48019
2025-11-10 09:44:42 +01:00
Stéphane Nicoll 4e1c2f07ce Upgrade to Micrometer 1.14.13
Closes gh-48018
2025-11-10 09:44:38 +01:00
Stéphane Nicoll de0445ce89 Upgrade to Jackson Bom 2.18.5
Closes gh-48017
2025-11-10 09:44:34 +01:00
Stéphane Nicoll a7563000b5 Upgrade to Hibernate 6.6.34.Final
Closes gh-48016
2025-11-10 09:44:31 +01:00
Stéphane Nicoll 66f7080a0b Upgrade to AspectJ 1.9.25
Closes gh-48015
2025-11-10 09:44:27 +01:00
Stéphane Nicoll 3c54e8403c Upgrade to Reactor Bom 2024.0.12
Closes gh-48014
2025-11-10 09:33:35 +01:00
Stéphane Nicoll 214f19ace9 Upgrade to R2DBC Postgresql 1.0.9.RELEASE
Closes gh-48013
2025-11-10 09:33:35 +01:00
Stéphane Nicoll 2e562d2c74 Upgrade to Quartz 2.5.1
Closes gh-48012
2025-11-10 09:33:35 +01:00
Stéphane Nicoll b3c4d1b066 Upgrade to MySQL 9.5.0
Closes gh-48011
2025-11-10 09:07:12 +01:00
Stéphane Nicoll 46cac91fa7 Upgrade to Micrometer Tracing 1.5.6
Closes gh-48010
2025-11-10 09:07:08 +01:00
Stéphane Nicoll 26ec5c0930 Upgrade to Micrometer 1.15.6
Closes gh-48009
2025-11-10 09:07:04 +01:00
Stéphane Nicoll 7b006ed8f5 Upgrade to Jackson Bom 2.19.4
Closes gh-48008
2025-11-10 09:07:00 +01:00
Stéphane Nicoll f7f9642131 Upgrade to Caffeine 3.2.3
Closes gh-48006
2025-11-10 09:04:14 +01:00
Stéphane Nicoll 923e6e71b4 Upgrade to AspectJ 1.9.25
Closes gh-48005
2025-11-10 09:04:10 +01:00
Stéphane Nicoll 5d84e491b6 Upgrade to Reactor Bom 2025.0.0
Closes gh-47822
2025-11-09 13:14:51 +01:00
Stéphane Nicoll ecb4e57a43 Upgrade to Micrometer Tracing 1.6.0
Closes gh-47821
2025-11-09 13:14:51 +01:00
Stéphane Nicoll b2c44ceac0 Upgrade to Micrometer 1.16.0
Closes gh-47820
2025-11-09 13:14:51 +01:00
Stéphane Nicoll 96457f4665 Merge branch '3.5.x'
Closes gh-47996
2025-11-09 12:16:47 +01:00
Stéphane Nicoll 65a27c2812 Merge pull request #47987 from nosan
* pr/47987:
  Polish contribution
  Allow Devtools Restarter to work with a parameterless main method

Closes gh-47987
2025-11-09 12:12:31 +01:00
Stéphane Nicoll 9ab77c75cf Polish contribution
See gh-47987
2025-11-09 12:11:54 +01:00
Dmytro Nosan bf0152e67c Allow Devtools Restarter to work with a parameterless main method
See gh-47987

Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
2025-11-09 12:10:26 +01:00
Stéphane Nicoll 4e834f339d Merge pull request #47991 from scottfrederick
* pr/47991:
  Remove Kafka libraries for Scala 2.12 from dependency management

Closes gh-47991
2025-11-09 11:53:57 +01:00
Scott Frederick a54152c6c9 Remove Kafka libraries for Scala 2.12 from dependency management
Kafka 4.0 dropped support for Scala 2.12, so the
`kafka-streams-scala_2.12` and `kafka_2.12` libraries should not be
dependency-managed along with the rest of the Kafka 4.1.0 libraries.

See gh-47991

Signed-off-by: Scott Frederick <scottyfred@gmail.com>
2025-11-09 11:52:39 +01:00
Phillip Webb 1da6296c95 Merge branch '3.5.x'
Closes gh-47994
2025-11-07 19:15:15 -08:00
Phillip Webb b9216a05e6 Merge branch '3.4.x' into 3.5.x
Closes gh-47993
2025-11-07 19:14:55 -08:00
Phillip Webb 046d4fd22b Upgrade to Antora 3.2.0-alpha.10 (with related extensions)
Closes gh-47417
2025-11-07 19:13:16 -08:00
Phillip Webb 830768d8da Merge branch '3.5.x' 2025-11-07 12:32:28 -08:00
Phillip Webb 2d7c2776fe Merge branch '3.4.x' into 3.5.x 2025-11-07 12:32:22 -08:00
Phillip Webb 5dac202e80 Upgrade Antora extensions
See gh-47417
2025-11-07 12:32:09 -08:00
Andy Wilkinson 07b13a40b1 Use separate Jakarta Mail API and Angus Mail dependencies
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:25], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:17], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
Run CodeQL Analysis / run-analysis (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:17]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Has been cancelled Details
Build and Deploy Snapshot / Trigger Docs Build (push) Has been cancelled Details
Build and Deploy Snapshot / Verify (push) Has been cancelled Details
Closes gh-47983
2025-11-07 14:34:10 +00:00
Stéphane Nicoll c0d18f7d46 Simplify configuration metadata changelog configuration 2025-11-07 14:36:41 +01:00
Moritz Halbritter c2db108502 Move reactor-test to spring-boot-starter-data-mongodb-reactive-test
Closes gh-47982
2025-11-07 10:29:50 +01:00
361 changed files with 5453 additions and 3477 deletions

View File

@ -126,7 +126,7 @@ jobs:
- name: Publish to SDKMAN!
uses: ./.github/actions/publish-to-sdkman
with:
make-default: false
make-default: true
sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }}
sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }}
spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}

1848
antora/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,18 @@
{
"scripts": {
"antora": "node npm/antora.js",
"postinstall": "patch-package"
"antora": "node npm/antora.js"
},
"dependencies": {
"@antora/cli": "3.2.0-alpha.10",
"@antora/site-generator": "3.2.0-alpha.4",
"@antora/site-generator": "3.2.0-alpha.10",
"@antora/atlas-extension": "1.0.0-alpha.5",
"@springio/antora-extensions": "1.14.7",
"@springio/antora-xref-extension": "1.0.0-alpha.4",
"@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.8",
"@springio/antora-xref-extension": "1.0.0-alpha.5",
"@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.10",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/asciidoctor-extensions": "1.0.0-alpha.17",
"patch-package": "^8.0.1"
"@springio/asciidoctor-extensions": "1.0.0-alpha.17"
},
"config": {
"ui-bundle-url": "https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.18/ui-bundle.zip"
"ui-bundle-url": "https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.24/ui-bundle.zip"
}
}

View File

@ -1,285 +0,0 @@
diff --git a/node_modules/@vscode/gulp-vinyl-zip/lib/src/index.js b/node_modules/@vscode/gulp-vinyl-zip/lib/src/index.js
index 17d902d..0448dec 100644
--- a/node_modules/@vscode/gulp-vinyl-zip/lib/src/index.js
+++ b/node_modules/@vscode/gulp-vinyl-zip/lib/src/index.js
@@ -1,135 +1,157 @@
-'use strict';
-
-var fs = require('fs');
-var constants = fs.constants;
-var yauzl = require('yauzl');
-var File = require('../vinyl-zip');
-var queue = require('queue');
-var through = require('through');
-var map = require('through2').obj;
-
-function modeFromEntry(entry) {
- var attr = entry.externalFileAttributes >> 16 || 33188;
-
- // The following constants are not available on all platforms:
- // 448 = constants.S_IRWXU, 56 = constants.S_IRWXG, 7 = constants.S_IRWXO
- return [448, 56, 7]
- .map(function (mask) { return attr & mask; })
- .reduce(function (a, b) { return a + b; }, attr & constants.S_IFMT);
+'use strict'
+
+// This is fork of vinyl-zip with the following updates:
+// - unzipFile has an additional `.on('error'` handler
+// - toStream has an additional `zip.on('error'` handler
+
+const fs = require('fs')
+const constants = fs.constants
+const yauzl = require('yauzl')
+const File = require('vinyl')
+const queue = require('queue')
+const through = require('through')
+const map = require('through2').obj
+
+function modeFromEntry (entry) {
+ const attr = entry.externalFileAttributes >> 16 || 33188
+ return [448, 56, 7]
+ .map(function (mask) {
+ return attr & mask
+ })
+ .reduce(function (a, b) {
+ return a + b
+ }, attr & constants.S_IFMT)
}
-function mtimeFromEntry(entry) {
- return yauzl.dosDateTimeToDate(entry.lastModFileDate, entry.lastModFileTime);
+function mtimeFromEntry (entry) {
+ return yauzl.dosDateTimeToDate(entry.lastModFileDate, entry.lastModFileTime)
}
-function toStream(zip) {
- var result = through();
- var q = queue();
- var didErr = false;
-
- q.on('error', function (err) {
- didErr = true;
- result.emit('error', err);
- });
-
- zip.on('entry', function (entry) {
- if (didErr) { return; }
-
- var stat = new fs.Stats();
- stat.mode = modeFromEntry(entry);
- stat.mtime = mtimeFromEntry(entry);
-
- // directories
- if (/\/$/.test(entry.fileName)) {
- stat.mode = (stat.mode & ~constants.S_IFMT) | constants.S_IFDIR;
- }
-
- var file = {
- path: entry.fileName,
- stat: stat
- };
-
- if (stat.isFile()) {
- stat.size = entry.uncompressedSize;
- if (entry.uncompressedSize === 0) {
- file.contents = Buffer.alloc(0);
- result.emit('data', new File(file));
- } else {
- q.push(function (cb) {
- zip.openReadStream(entry, function (err, readStream) {
- if (err) { return cb(err); }
- file.contents = readStream;
- result.emit('data', new File(file));
- cb();
- });
- });
-
- q.start();
- }
- } else if (stat.isSymbolicLink()) {
- stat.size = entry.uncompressedSize;
- q.push(function (cb) {
- zip.openReadStream(entry, function (err, readStream) {
- if (err) { return cb(err); }
- file.symlink = '';
- readStream.on('data', function (c) { file.symlink += c; });
- readStream.on('error', cb);
- readStream.on('end', function () {
- result.emit('data', new File(file));
- cb();
- });
- });
- });
-
- q.start();
- } else if (stat.isDirectory()) {
- result.emit('data', new File(file));
- } else {
- result.emit('data', new File(file));
- }
- });
-
- zip.on('end', function () {
- if (didErr) {
- return;
- }
-
- if (q.length === 0) {
- result.end();
- } else {
- q.on('end', function () {
- result.end();
- });
- }
- });
-
- return result;
+function toStream (zip) {
+ const result = through()
+ const q = queue()
+ let didErr = false
+
+ q.on('error', function (err) {
+ didErr = true
+ result.emit('error', err)
+ })
+
+ zip.on('error', function (err) {
+ didErr = true
+ result.emit('error', err)
+ })
+
+ zip.on('entry', function (entry) {
+ if (didErr) {
+ return
+ }
+
+ const stat = new fs.Stats()
+ stat.mode = modeFromEntry(entry)
+ stat.mtime = mtimeFromEntry(entry)
+
+ // directories
+ if (/\/$/.test(entry.fileName)) {
+ stat.mode = (stat.mode & ~constants.S_IFMT) | constants.S_IFDIR
+ }
+
+ const file = {
+ path: entry.fileName,
+ stat,
+ }
+
+ if (stat.isFile()) {
+ stat.size = entry.uncompressedSize
+ if (entry.uncompressedSize === 0) {
+ file.contents = Buffer.alloc(0)
+ result.emit('data', new File(file))
+ } else {
+ q.push(function (cb) {
+ zip.openReadStream(entry, function (err, readStream) {
+ if (err) {
+ return cb(err)
+ }
+ file.contents = readStream
+ result.emit('data', new File(file))
+ cb()
+ })
+ })
+
+ q.start()
+ }
+ } else if (stat.isSymbolicLink()) {
+ stat.size = entry.uncompressedSize
+ q.push(function (cb) {
+ zip.openReadStream(entry, function (err, readStream) {
+ if (err) {
+ return cb(err)
+ }
+ file.symlink = ''
+ readStream.on('data', function (c) {
+ file.symlink += c
+ })
+ readStream.on('error', cb)
+ readStream.on('end', function () {
+ result.emit('data', new File(file))
+ cb()
+ })
+ })
+ })
+
+ q.start()
+ } else if (stat.isDirectory()) {
+ result.emit('data', new File(file))
+ } else {
+ result.emit('data', new File(file))
+ }
+ })
+
+ zip.on('end', function () {
+ if (didErr) {
+ return
+ }
+
+ if (q.length === 0) {
+ result.end()
+ } else {
+ q.on('end', function () {
+ result.end()
+ })
+ }
+ })
+
+ return result
}
-function unzipFile(zipPath) {
- var result = through();
- yauzl.open(zipPath, function (err, zip) {
- if (err) { return result.emit('error', err); }
- toStream(zip).pipe(result);
- });
- return result;
+function unzipFile (zipPath) {
+ const result = through()
+ yauzl.open(zipPath, function (err, zip) {
+ if (err) {
+ return result.emit('error', err)
+ }
+ toStream(zip)
+ .on('error', (err) => result.emit('error', err))
+ .pipe(result)
+ })
+ return result
}
-function unzip() {
- return map(function (file, enc, next) {
- if (!file.isBuffer()) return next(new Error('Only supports buffers'));
- yauzl.fromBuffer(file.contents, (err, zip) => {
- if (err) return this.emit('error', err);
- toStream(zip)
- .on('error', next)
- .on('data', (data) => this.push(data))
- .on('end', next);
- });
- });
+function unzip () {
+ return map(function (file, enc, next) {
+ if (!file.isBuffer()) return next(new Error('Only supports buffers'))
+ yauzl.fromBuffer(file.contents, (err, zip) => {
+ if (err) return this.emit('error', err)
+ toStream(zip)
+ .on('error', next)
+ .on('data', (data) => this.push(data))
+ .on('end', next)
+ })
+ })
}
-function src(zipPath) {
- return zipPath ? unzipFile(zipPath) : unzip();
+function src (zipPath) {
+ return zipPath ? unzipFile(zipPath) : unzip()
}
-module.exports = src;
+module.exports = src

View File

@ -2,7 +2,6 @@
<settings defaultResolver="chain" />
<resolvers>
<chain name="chain">
<!-- NOTE: You should declare only repositories that you need here -->
<filesystem name="local" local="true" m2compatible="true">
<artifact pattern="${user.home}/.m2/[organisation]/[module]/[revision]/[module]-[revision].[ext]" />
<ivy pattern="${user.home}/.m2/[organisation]/[module]/[revision]/[module]-[revision].pom" />
@ -11,6 +10,5 @@
<!-- {spring.mavenRepositories} -->
</chain>
</resolvers>
<credentials host="${env.COMMERCIAL_RELEASE_REPO_URL}" username="${env.COMMERCIAL_REPO_USERNAME}" passwd="${env.COMMERCIAL_REPO_PASSWORD}"/>
<credentials host="${env.COMMERCIAL_SNAPSHOT_REPO_URL}" username="${env.COMMERCIAL_REPO_USERNAME}" passwd="${env.COMMERCIAL_REPO_PASSWORD}"/>
<!-- {spring.mavenCredentials} -->
</ivysettings>

View File

@ -23,7 +23,7 @@ apply plugin: 'io.spring.dependency-management'
// tag::dependencies[]
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
providedRuntime('org.springframework.boot:spring-boot-tomcat-runtime')
implementation('org.springframework.boot:spring-boot-starter-webmvc')
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat-runtime')
}
// end::dependencies[]

View File

@ -8,6 +8,6 @@ apply(plugin = "io.spring.dependency-management")
// tag::dependencies[]
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
providedRuntime("org.springframework.boot:spring-boot-tomcat-runtime")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat-runtime")
}
// end::dependencies[]

View File

@ -27,7 +27,7 @@ The `assemble` task is automatically configured to depend upon the `bootWar` tas
=== Packaging Executable and Deployable Wars
A war file can be packaged such that it can be executed using `java -jar` and deployed to an external container.
To do so, the embedded servlet runtime should be added to the `providedRuntime` configuration, for example:
To do so, the embedded servlet container runtime should be added to the `providedRuntime` configuration, for example:
[tabs]
======
@ -45,7 +45,7 @@ include::example$packaging/war-container-dependency.gradle.kts[tags=dependencies
----
======
This ensures that the runtime is packaged in the war file's `WEB-INF/lib-provided` directory from where it will not conflict with the external container's own classes.
This ensures that the runtime jars are packaged in the war file's `WEB-INF/lib-provided` directory from where they will not conflict with the external container's own classes.
NOTE: `providedRuntime` is preferred to Gradle's `compileOnly` configuration as, among other limitations, `compileOnly` dependencies are not on the test classpath so any web-based integration tests will fail.

View File

@ -86,6 +86,8 @@ class WarPluginAction implements PluginApplicationAction {
.minus((developmentOnly.minus(productionRuntimeClasspath)))
.minus((testAndDevelopmentOnly.minus(productionRuntimeClasspath)))
.filter(new JarTypeFileSpec());
Callable<FileCollection> providedClasspath = () -> providedRuntimeConfiguration(project)
.filter(new JarTypeFileSpec());
TaskProvider<ResolveMainClassName> resolveMainClassName = project.getTasks()
.named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class);
TaskProvider<BootWar> bootWarProvider = project.getTasks()
@ -93,7 +95,7 @@ class WarPluginAction implements PluginApplicationAction {
bootWar.setGroup(BasePlugin.BUILD_GROUP);
bootWar.setDescription("Assembles an executable war archive containing webapp"
+ " content, and the main classes and their dependencies.");
bootWar.providedClasspath(providedRuntimeConfiguration(project));
bootWar.providedClasspath(providedClasspath);
bootWar.setClasspath(classpath);
Provider<String> manifestStartClass = project
.provider(() -> (String) bootWar.getManifest().getAttributes().get("Start-Class"));

View File

@ -64,6 +64,7 @@ import org.springframework.boot.loader.tools.ReachabilityMetadataProperties;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.function.ThrowingSupplier;
/**
* A {@link CopyAction} for creating a Spring Boot zip archive (typically a jar or war).
@ -325,7 +326,7 @@ class BootZipCopyAction implements CopyAction {
private void writeJarModeLibrary(String location, JarModeLibrary library) throws IOException {
String name = location + library.getName();
writeEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false,
(entry) -> prepareStoredEntry(library.openStream(), false, entry));
(entry) -> prepareStoredEntry(library::openStream, false, entry));
if (BootZipCopyAction.this.layerResolver != null) {
Layer layer = BootZipCopyAction.this.layerResolver.getLayer(library);
Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
@ -429,12 +430,12 @@ class BootZipCopyAction implements CopyAction {
}
private void prepareStoredEntry(FileCopyDetails details, ZipArchiveEntry archiveEntry) throws IOException {
prepareStoredEntry(details.open(), BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),
prepareStoredEntry(details::open, BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),
archiveEntry);
}
private void prepareStoredEntry(InputStream input, boolean unpack, ZipArchiveEntry archiveEntry)
throws IOException {
private void prepareStoredEntry(ThrowingSupplier<InputStream> input, boolean unpack,
ZipArchiveEntry archiveEntry) throws IOException {
new StoredEntryPreparator(input, unpack).prepareStoredEntry(archiveEntry);
}
@ -564,10 +565,10 @@ class BootZipCopyAction implements CopyAction {
private long size;
StoredEntryPreparator(InputStream inputStream, boolean unpack) throws IOException {
StoredEntryPreparator(ThrowingSupplier<InputStream> input, boolean unpack) throws IOException {
this.unpack = unpack;
try (inputStream) {
load(inputStream);
try (InputStream stream = input.get()) {
load(stream);
}
}

View File

@ -56,7 +56,7 @@ import org.springframework.boot.testsupport.gradle.testkit.GradleBuild;
*/
public class PluginClasspathGradleBuild extends GradleBuild {
private boolean kotlin = false;
private boolean kotlin;
public PluginClasspathGradleBuild(BuildOutput buildOutput) {
super(buildOutput);

View File

@ -87,8 +87,8 @@ class SpringRepositoriesExtension {
addRepositories { }
}
def mavenRepositories(condition) {
if (condition) addRepositories { }
def mavenRepositoriesFor(version) {
addRepositories(version) { }
}
def mavenRepositoriesExcludingBootGroup() {
@ -100,9 +100,13 @@ class SpringRepositoriesExtension {
}
private void addRepositories(action) {
addCommercialRepository("release", false, "/spring-enterprise-maven-prod-local", action)
if (this.version.endsWith("-SNAPSHOT")) {
addCommercialRepository("snapshot", true, "/spring-enterprise-maven-dev-local", action)
addRepositories(this.version, action)
}
private void addRepositories(version, action) {
addCommercialRepositoryIfNecessary("release", false, "/spring-enterprise-maven-prod-local", action)
if (version.endsWith("-SNAPSHOT")) {
addCommercialRepositoryIfNecessary("snapshot", true, "/spring-enterprise-maven-dev-local", action)
addOssRepository("snapshot", true, "/snapshot", action)
}
}
@ -113,7 +117,7 @@ class SpringRepositoriesExtension {
addRepository(name, snapshot, url, action)
}
private void addCommercialRepository(id, snapshot, path, action) {
private void addCommercialRepositoryIfNecessary(id, snapshot, path, action) {
if (!"commercial".equalsIgnoreCase(this.buildType)) return
def name = "spring-commercial-" + id
def url = fromEnv("COMMERCIAL_%SREPO_URL", id, "https://usw1.packages.broadcom.com" + path)

View File

@ -24,6 +24,7 @@ plugins {
repositories {
mavenCentral()
spring.mavenRepositoriesFor("${springFrameworkVersion}")
gradlePluginPortal()
}
@ -32,10 +33,6 @@ java {
targetCompatibility = 17
}
repositories {
spring.mavenRepositories("${springFrameworkVersion}".contains("-"))
}
checkstyle {
toolVersion = "${checkstyleToolVersion}"
}
@ -114,6 +111,10 @@ gradlePlugin {
id = "org.springframework.boot.bom"
implementationClass = "org.springframework.boot.build.bom.BomPlugin"
}
configurationMetadataPlugin {
id = "org.springframework.boot.configuration-metadata"
implementationClass = "org.springframework.boot.build.context.properties.ConfigurationMetadataPlugin"
}
configurationPropertiesPlugin {
id = "org.springframework.boot.configuration-properties"
implementationClass = "org.springframework.boot.build.context.properties.ConfigurationPropertiesPlugin"

View File

@ -230,10 +230,18 @@ class JavaConventions {
CoreJavadocOptions options = (CoreJavadocOptions) javadoc.getOptions();
options.source("17");
options.encoding("UTF-8");
options.addStringOption("Xdoclint:none", "-quiet");
addValuelessOption(options, "Xdoclint:none");
addValuelessOption(options, "quiet");
if (!javadoc.getName().contains("aggregated")) {
addValuelessOption(options, "-no-fonts");
}
});
}
private void addValuelessOption(CoreJavadocOptions options, String option) {
options.addMultilineMultiValueOption(option).setValue(List.of(Collections.emptyList()));
}
private void configureJavaConventions(Project project) {
if (!project.hasProperty("toolchainVersion")) {
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);

View File

@ -20,7 +20,9 @@ import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
@ -37,6 +39,8 @@ import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
*/
public class RepositoryTransformersExtension {
private static final String CREDENTIALS_MARKER = "{spring.mavenCredentials}";
private static final String REPOSITORIES_MARKER = "{spring.mavenRepositories}";
private static final String PLUGIN_REPOSITORIES_MARKER = "{spring.mavenPluginRepositories}";
@ -60,6 +64,19 @@ public class RepositoryTransformersExtension {
return "%s<ibiblio name=\"%s\" m2compatible=\"true\" root=\"%s\" />".formatted(indent, name, url);
});
}
if (line.contains(CREDENTIALS_MARKER)) {
Map<String, MavenCredential> hostCredentials = new LinkedHashMap<>();
getSpringRepositories().forEach((repository) -> {
if (repository.getName().startsWith("spring-commercial-")) {
String host = repository.getUrl().getHost();
hostCredentials.put(host,
new MavenCredential("${env.COMMERCIAL_REPO_USERNAME}", "${env.COMMERCIAL_REPO_PASSWORD"));
}
});
return transform(line, hostCredentials.entrySet(), (entry,
indent) -> "%s<credentials host=\"%s\" realm=\"Artifactory Realm\" username=\"%s\" passwd=\"%s\" />%n"
.formatted(indent, entry.getKey(), entry.getValue().username(), entry.getValue().password()));
}
return line;
}
@ -99,10 +116,14 @@ public class RepositoryTransformersExtension {
}
private String transform(String line, BiFunction<MavenArtifactRepository, String, String> generator) {
return transform(line, getSpringRepositories(), generator);
}
private <T> String transform(String line, Iterable<T> iterable, BiFunction<T, String, String> generator) {
StringBuilder result = new StringBuilder();
String indent = getIndent(line);
getSpringRepositories().forEach((repository) -> {
String fragment = generator.apply(repository, indent);
iterable.forEach((item) -> {
String fragment = generator.apply(item, indent);
if (fragment != null) {
result.append(!result.isEmpty() ? "\n" : "");
result.append(fragment);
@ -136,4 +157,8 @@ public class RepositoryTransformersExtension {
project.getExtensions().create("springRepositoryTransformers", RepositoryTransformersExtension.class, project);
}
record MavenCredential(String username, String password) {
}
}

View File

@ -26,6 +26,7 @@ import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import java.util.stream.Stream;
@ -42,6 +43,7 @@ import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.SetProperty;
@ -72,19 +74,27 @@ import org.gradle.api.tasks.VerificationException;
*/
public abstract class ArchitectureCheck extends DefaultTask {
static final String CONDITIONAL_ON_CLASS = "ConditionalOnClass";
static final String DEPRECATED_CONFIGURATION_PROPERTY = "DeprecatedConfigurationProperty";
private static final String CONDITIONAL_ON_CLASS_ANNOTATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnClass";
private static final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.context.properties.DeprecatedConfigurationProperty";
private FileCollection classes;
public ArchitectureCheck() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
getConditionalOnClassAnnotation().convention(CONDITIONAL_ON_CLASS_ANNOTATION);
getAnnotationClasses().convention(Map.of(CONDITIONAL_ON_CLASS, CONDITIONAL_ON_CLASS_ANNOTATION,
DEPRECATED_CONFIGURATION_PROPERTY, DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION));
getRules().addAll(getProhibitObjectsRequireNonNull().convention(true)
.map(whenTrue(ArchitectureRules::noClassesShouldCallObjectsRequireNonNull)));
getRules().addAll(ArchitectureRules.standard());
getRules().addAll(whenMainSources(() -> List
.of(ArchitectureRules.allBeanMethodsShouldReturnNonPrivateType(), ArchitectureRules
.allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(getConditionalOnClassAnnotation().get()))));
getRules().addAll(whenMainSources(() -> ArchitectureRules
.beanMethods(annotationClassFor(CONDITIONAL_ON_CLASS, CONDITIONAL_ON_CLASS_ANNOTATION))));
getRules().addAll(whenMainSources(() -> ArchitectureRules.configurationProperties(
annotationClassFor(DEPRECATED_CONFIGURATION_PROPERTY, DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION))));
getRules().addAll(and(getNullMarkedEnabled(), isMainSourceSet()).map(whenTrue(() -> Collections.singletonList(
ArchitectureRules.packagesShouldBeAnnotatedWithNullMarked(getNullMarkedIgnoredPackages().get())))));
getRuleDescriptions().set(getRules().map(this::asDescriptions));
@ -110,6 +120,10 @@ public abstract class ArchitectureCheck extends DefaultTask {
return rules.stream().map(ArchRule::getDescription).toList();
}
private String annotationClassFor(String name, String defaultValue) {
return getAnnotationClasses().get().getOrDefault(name, defaultValue);
}
@TaskAction
void checkArchitecture() throws Exception {
withCompileClasspath(() -> {
@ -209,7 +223,7 @@ public abstract class ArchitectureCheck extends DefaultTask {
@Internal
abstract SetProperty<String> getNullMarkedIgnoredPackages();
@Internal
abstract Property<String> getConditionalOnClassAnnotation();
@Input
abstract MapProperty<String, String> getAnnotationClasses();
}

View File

@ -16,17 +16,17 @@
package org.springframework.boot.build.architecture;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool;
import org.springframework.util.StringUtils;
@ -46,28 +46,45 @@ public class ArchitecturePlugin implements Plugin<Project> {
private void registerTasks(Project project, ArchitectureCheckExtension extension) {
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
List<TaskProvider<ArchitectureCheck>> packageTangleChecks = new ArrayList<>();
for (SourceSet sourceSet : javaPluginExtension.getSourceSets()) {
TaskProvider<ArchitectureCheck> checkPackageTangles = project.getTasks()
.register("checkArchitecture" + StringUtils.capitalize(sourceSet.getName()), ArchitectureCheck.class,
(task) -> {
task.getSourceSet().set(sourceSet.getName());
task.getCompileClasspath().from(sourceSet.getCompileClasspath());
task.setClasses(sourceSet.getOutput().getClassesDirs());
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
task.dependsOn(sourceSet.getProcessResourcesTaskName());
task.setDescription("Checks the architecture of the classes of the " + sourceSet.getName()
+ " source set.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
task.getNullMarkedEnabled().set(extension.getNullMarked().getEnabled());
task.getNullMarkedIgnoredPackages().set(extension.getNullMarked().getIgnoredPackages());
});
packageTangleChecks.add(checkPackageTangles);
}
if (!packageTangleChecks.isEmpty()) {
TaskProvider<Task> checkTask = project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME);
checkTask.configure((check) -> check.dependsOn(packageTangleChecks));
registerArchitectureCheck(sourceSet, "java", project).configure((task) -> {
task.setClasses(project.files(project.getTasks()
.named(sourceSet.getCompileTaskName("java"), JavaCompile.class)
.flatMap((compile) -> compile.getDestinationDirectory())));
task.getNullMarkedEnabled().set(extension.getNullMarked().getEnabled());
task.getNullMarkedIgnoredPackages().set(extension.getNullMarked().getIgnoredPackages());
});
project.getPlugins()
.withId("org.jetbrains.kotlin.jvm",
(kotlinPlugin) -> registerArchitectureCheck(sourceSet, "kotlin", project).configure((task) -> {
task.setClasses(project.files(project.getTasks()
.named(sourceSet.getCompileTaskName("kotlin"), KotlinCompileTool.class)
.flatMap((compile) -> compile.getDestinationDirectory())));
task.getNullMarkedEnabled().set(false);
task.getNullMarkedIgnoredPackages().set(Collections.emptySet());
}));
}
}
private TaskProvider<ArchitectureCheck> registerArchitectureCheck(SourceSet sourceSet, String language,
Project project) {
TaskProvider<ArchitectureCheck> checkArchitecture = project.getTasks()
.register(
"checkArchitecture"
+ StringUtils.capitalize(sourceSet.getName() + StringUtils.capitalize(language)),
ArchitectureCheck.class, (task) -> {
task.getSourceSet().set(sourceSet.getName());
task.getCompileClasspath().from(sourceSet.getCompileClasspath());
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
task.dependsOn(sourceSet.getProcessResourcesTaskName());
task.setDescription("Checks the architecture of the " + language + " classes of the "
+ sourceSet.getName() + " source set.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
});
project.getTasks()
.named(LifecycleBasePlugin.CHECK_TASK_NAME)
.configure((check) -> check.dependsOn(checkArchitecture));
return checkArchitecture;
}
}

View File

@ -116,7 +116,16 @@ final class ArchitectureRules {
return List.copyOf(rules);
}
static ArchRule allBeanMethodsShouldReturnNonPrivateType() {
static List<ArchRule> beanMethods(String annotationName) {
return List.of(allBeanMethodsShouldReturnNonPrivateType(),
allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(annotationName));
}
static List<ArchRule> configurationProperties(String annotationName) {
return List.of(allDeprecatedConfigurationPropertiesShouldIncludeSince(annotationName));
}
private static ArchRule allBeanMethodsShouldReturnNonPrivateType() {
return methodsThatAreAnnotatedWith("org.springframework.context.annotation.Bean").should(check(
"not return types declared with the %s modifier, as such types are incompatible with Spring AOT processing"
.formatted(JavaModifier.PRIVATE),
@ -130,7 +139,7 @@ final class ArchitectureRules {
.allowEmptyShould(true);
}
static ArchRule allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(String annotationName) {
private static ArchRule allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(String annotationName) {
return methodsThatAreAnnotatedWith("org.springframework.context.annotation.Bean").should()
.notBeAnnotatedWith(annotationName)
.because("@ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent "
@ -374,6 +383,20 @@ final class ArchitectureRules {
.allowEmptyShould(true);
}
private static ArchRule allDeprecatedConfigurationPropertiesShouldIncludeSince(String annotationName) {
return methodsThatAreAnnotatedWith(annotationName)
.should(check("include a non-empty 'since' attribute", (method, events) -> {
JavaAnnotation<JavaMethod> annotation = method.getAnnotationOfType(annotationName);
Map<String, Object> properties = annotation.getProperties();
Object since = properties.get("since");
if (!(since instanceof String) || ((String) since).isEmpty()) {
addViolation(events, method, annotation.getDescription()
+ " should include a non-empty 'since' attribute of @DeprecatedConfigurationProperty");
}
}))
.allowEmptyShould(true);
}
private static ArchRule autoConfigurationClassesShouldBePublicAndFinal() {
return ArchRuleDefinition.classes()
.that(areRegularAutoConfiguration())
@ -398,6 +421,8 @@ final class ArchitectureRules {
return ArchRuleDefinition.members()
.that()
.areDeclaredInClassesThat(areRegularAutoConfiguration())
.and()
.areDeclaredInClassesThat(areNotKotlinClasses())
.and(areNotDefaultConstructors())
.and(areNotConstants())
.and(dontOverridePublicMethods())
@ -417,13 +442,18 @@ final class ArchitectureRules {
}
static DescribedPredicate<JavaClass> areRegularAutoConfiguration() {
return DescribedPredicate.describe("Regular @AutoConfiguration",
return DescribedPredicate.describe("are regular @AutoConfiguration",
(javaClass) -> javaClass.isAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)
&& !javaClass.getName().contains("TestAutoConfiguration") && !javaClass.isAnnotation());
}
static DescribedPredicate<JavaClass> areNotKotlinClasses() {
return DescribedPredicate.describe("are not Kotlin classes",
(javaClass) -> !javaClass.isAnnotatedWith("kotlin.Metadata"));
}
static DescribedPredicate<JavaClass> areTestAutoConfiguration() {
return DescribedPredicate.describe("Test @AutoConfiguration",
return DescribedPredicate.describe("are test @AutoConfiguration",
(javaClass) -> javaClass.isAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)
&& javaClass.getName().contains("TestAutoConfiguration") && !javaClass.isAnnotation());
}

View File

@ -31,12 +31,16 @@ import org.springframework.util.ReflectionUtils;
/**
* Finds all configurations from auto-configurations (either nested configurations or
* imported ones) and checks that these classes don't contain public members.
* <p>
* Kotlin classes are ignored as Kotlin does not have package-private visibility and
* {@code internal} isn't a good substitute.
*
* @author Moritz Halbritter
*/
class AutoConfigurationChecker {
private final DescribedPredicate<JavaClass> isAutoConfiguration = ArchitectureRules.areRegularAutoConfiguration();
private final DescribedPredicate<JavaClass> isAutoConfiguration = ArchitectureRules.areRegularAutoConfiguration()
.and(ArchitectureRules.areNotKotlinClasses());
EvaluationResult check(JavaClasses javaClasses) {
AutoConfigurations autoConfigurations = new AutoConfigurations();

View File

@ -18,15 +18,6 @@ package org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.gradle.api.file.FileTree;
import org.gradle.api.file.RegularFileProperty;
@ -37,8 +28,8 @@ import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import tools.jackson.core.StreamReadFeature;
import tools.jackson.databind.json.JsonMapper;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;
/**
* {@link SourceTask} that checks additional Spring configuration metadata files.
@ -65,98 +56,16 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
@TaskAction
void check() throws IOException {
Report report = createReport();
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(getSource().getFiles());
Report report = new Report(this.projectDir);
analyzer.analyzeSort(report);
analyzer.analyzeDeprecationSince(report);
File reportFile = getReportLocation().get().getAsFile();
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
report.write(reportFile);
if (report.hasProblems()) {
throw new VerificationException(
"Problems found in additional Spring configuration metadata. See " + reportFile + " for details.");
}
}
@SuppressWarnings("unchecked")
private Report createReport() {
JsonMapper jsonMapper = JsonMapper.builder().enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION).build();
Report report = new Report();
for (File file : getSource().getFiles()) {
Analysis analysis = report.analysis(this.projectDir.toPath().relativize(file.toPath()));
Map<String, Object> json = jsonMapper.readValue(file, Map.class);
check("groups", json, analysis);
check("properties", json, analysis);
check("hints", json, analysis);
}
return report;
}
@SuppressWarnings("unchecked")
private void check(String key, Map<String, Object> json, Analysis analysis) {
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.getOrDefault(key, Collections.emptyList());
List<String> names = groups.stream().map((group) -> (String) group.get("name")).toList();
List<String> sortedNames = sortedCopy(names);
for (int i = 0; i < names.size(); i++) {
String actual = names.get(i);
String expected = sortedNames.get(i);
if (!actual.equals(expected)) {
analysis.problems.add("Wrong order at $." + key + "[" + i + "].name - expected '" + expected
+ "' but found '" + actual + "'");
}
}
}
private List<String> sortedCopy(Collection<String> original) {
List<String> copy = new ArrayList<>(original);
Collections.sort(copy);
return copy;
}
private static final class Report implements Iterable<String> {
private final List<Analysis> analyses = new ArrayList<>();
private Analysis analysis(Path path) {
Analysis analysis = new Analysis(path);
this.analyses.add(analysis);
return analysis;
}
private boolean hasProblems() {
for (Analysis analysis : this.analyses) {
if (!analysis.problems.isEmpty()) {
return true;
}
}
return false;
}
@Override
public Iterator<String> iterator() {
List<String> lines = new ArrayList<>();
for (Analysis analysis : this.analyses) {
lines.add(analysis.source.toString());
lines.add("");
if (analysis.problems.isEmpty()) {
lines.add("No problems found.");
}
else {
lines.addAll(analysis.problems);
}
lines.add("");
}
return lines.iterator();
}
}
private static final class Analysis {
private final List<String> problems = new ArrayList<>();
private final Path source;
private Analysis(Path source) {
this.source = source;
}
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright 2025 the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
/**
* {@link Task} that checks aggregated Spring configuration metadata.
*
* @author Andy Wilkinson
*/
public abstract class CheckAggregatedSpringConfigurationMetadata extends DefaultTask {
private FileCollection configurationPropertyMetadata;
@OutputFile
public abstract RegularFileProperty getReportLocation();
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getConfigurationPropertyMetadata() {
return this.configurationPropertyMetadata;
}
public void setConfigurationPropertyMetadata(FileCollection configurationPropertyMetadata) {
this.configurationPropertyMetadata = configurationPropertyMetadata;
}
@TaskAction
void check() throws IOException {
Report report = createReport();
File reportFile = getReportLocation().get().getAsFile();
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
if (report.hasProblems()) {
throw new VerificationException(
"Problems found in aggregated Spring configuration metadata. See " + reportFile + " for details.");
}
}
private Report createReport() {
ConfigurationProperties configurationProperties = ConfigurationProperties
.fromFiles(this.configurationPropertyMetadata);
Set<String> propertyNames = configurationProperties.stream()
.map(ConfigurationProperty::getName)
.collect(Collectors.toSet());
List<ConfigurationProperty> missingReplacement = configurationProperties.stream()
.filter(ConfigurationProperty::isDeprecated)
.filter((deprecated) -> {
String replacement = deprecated.getDeprecation().replacement();
return replacement != null && !propertyNames.contains(replacement);
})
.toList();
return new Report(missingReplacement);
}
private static final class Report implements Iterable<String> {
private final List<ConfigurationProperty> propertiesWithMissingReplacement;
private Report(List<ConfigurationProperty> propertiesWithMissingReplacement) {
this.propertiesWithMissingReplacement = propertiesWithMissingReplacement;
}
private boolean hasProblems() {
return !this.propertiesWithMissingReplacement.isEmpty();
}
@Override
public Iterator<String> iterator() {
List<String> lines = new ArrayList<>();
if (this.propertiesWithMissingReplacement.isEmpty()) {
lines.add("No problems found.");
}
else {
lines.add("The following properties have a replacement that does not exist:");
lines.add("");
lines.addAll(this.propertiesWithMissingReplacement.stream()
.map((property) -> "\t" + property.getName() + " (replacement "
+ property.getDeprecation().replacement() + ")")
.toList());
}
lines.add("");
return lines.iterator();
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;
/**
* {@link SourceTask} that checks manual Spring configuration metadata files.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public abstract class CheckManualSpringConfigurationMetadata extends DefaultTask {
private final File projectDir;
public CheckManualSpringConfigurationMetadata() {
this.projectDir = getProject().getProjectDir();
}
@OutputFile
public abstract RegularFileProperty getReportLocation();
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
public abstract Property<File> getMetadataLocation();
@Input
public abstract ListProperty<String> getExclusions();
@TaskAction
void check() throws IOException {
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(
List.of(getMetadataLocation().get()));
Report report = new Report(this.projectDir);
analyzer.analyzeSort(report);
analyzer.analyzePropertyDescription(report, getExclusions().get());
analyzer.analyzeDeprecationSince(report);
File reportFile = getReportLocation().get().getAsFile();
report.write(reportFile);
if (report.hasProblems()) {
throw new VerificationException(
"Problems found in manual Spring configuration metadata. See " + reportFile + " for details.");
}
}
}

View File

@ -18,13 +18,7 @@ package org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
@ -37,7 +31,8 @@ import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import tools.jackson.databind.json.JsonMapper;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;
/**
* {@link SourceTask} that checks {@code spring-configuration-metadata.json} files.
@ -46,10 +41,10 @@ import tools.jackson.databind.json.JsonMapper;
*/
public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
private final Path projectRoot;
private final File projectRoot;
public CheckSpringConfigurationMetadata() {
this.projectRoot = getProject().getProjectDir().toPath();
this.projectRoot = getProject().getProjectDir();
}
@OutputFile
@ -64,86 +59,16 @@ public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
@TaskAction
void check() throws IOException {
Report report = createReport();
Report report = new Report(this.projectRoot);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(
List.of(getMetadataLocation().get().getAsFile()));
analyzer.analyzePropertyDescription(report, getExclusions().get());
File reportFile = getReportLocation().get().getAsFile();
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
report.write(reportFile);
if (report.hasProblems()) {
throw new VerificationException(
"Problems found in Spring configuration metadata. See " + reportFile + " for details.");
}
}
@SuppressWarnings("unchecked")
private Report createReport() {
JsonMapper jsonMapper = new JsonMapper();
File file = getMetadataLocation().get().getAsFile();
Report report = new Report(this.projectRoot.relativize(file.toPath()));
Map<String, Object> json = jsonMapper.readValue(file, Map.class);
List<Map<String, Object>> properties = (List<Map<String, Object>>) json.get("properties");
for (Map<String, Object> property : properties) {
String name = (String) property.get("name");
if (!isDeprecated(property) && !isDescribed(property) && !isExcluded(name)) {
report.propertiesWithNoDescription.add(name);
}
}
return report;
}
private boolean isExcluded(String propertyName) {
for (String exclusion : getExclusions().get()) {
if (propertyName.equals(exclusion)) {
return true;
}
if (exclusion.endsWith(".*")) {
if (propertyName.startsWith(exclusion.substring(0, exclusion.length() - 2))) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
private boolean isDeprecated(Map<String, Object> property) {
return (Map<String, Object>) property.get("deprecation") != null;
}
private boolean isDescribed(Map<String, Object> property) {
return property.get("description") != null;
}
private static final class Report implements Iterable<String> {
private final List<String> propertiesWithNoDescription = new ArrayList<>();
private final Path source;
private Report(Path source) {
this.source = source;
}
private boolean hasProblems() {
return !this.propertiesWithNoDescription.isEmpty();
}
@Override
public Iterator<String> iterator() {
List<String> lines = new ArrayList<>();
lines.add(this.source.toString());
lines.add("");
if (this.propertiesWithNoDescription.isEmpty()) {
lines.add("No problems found.");
}
else {
lines.add("The following properties have no description:");
lines.add("");
lines.addAll(this.propertiesWithNoDescription.stream().map((line) -> "\t" + line).toList());
}
lines.add("");
return lines.iterator();
}
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.context.properties;
import java.io.File;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.Usage;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.gradle.language.jvm.tasks.ProcessResources;
/**
* {@link Plugin} for projects that <em>only</em> define manual configuration metadata.
* When applied, the plugin registers a {@link CheckManualSpringConfigurationMetadata}
* task and configures the {@code check} task to depend upon it.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class ConfigurationMetadataPlugin implements Plugin<Project> {
private static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = "configurationPropertiesMetadata";
/**
* Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.
*/
public static final String CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkManualSpringConfigurationMetadata";
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerCheckAdditionalMetadataTask(project));
}
private void registerCheckAdditionalMetadataTask(Project project) {
TaskProvider<CheckManualSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()
.register(CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME,
CheckManualSpringConfigurationMetadata.class);
SourceSet mainSourceSet = project.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
Provider<File> manualMetadataLocation = project.getTasks()
.named(mainSourceSet.getProcessResourcesTaskName(), ProcessResources.class)
.map((processResources) -> new File(processResources.getDestinationDir(),
"META-INF/spring-configuration-metadata.json"));
checkConfigurationMetadata.configure((check) -> {
check.getMetadataLocation().set(manualMetadataLocation);
check.getReportLocation()
.set(project.getLayout()
.getBuildDirectory()
.file("reports/manual-spring-configuration-metadata/check.txt"));
});
addMetadataArtifact(project, manualMetadataLocation);
project.getTasks()
.named(LifecycleBasePlugin.CHECK_TASK_NAME)
.configure((check) -> check.dependsOn(checkConfigurationMetadata));
}
private void addMetadataArtifact(Project project, Provider<File> metadataLocation) {
project.getConfigurations()
.consumable(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, (configuration) -> {
configuration.attributes((attributes) -> {
attributes.attribute(Category.CATEGORY_ATTRIBUTE,
project.getObjects().named(Category.class, Category.DOCUMENTATION));
attributes.attribute(Usage.USAGE_ATTRIBUTE,
project.getObjects().named(Usage.class, "configuration-properties-metadata"));
});
});
project.getArtifacts().add(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, metadataLocation);
}
}

View File

@ -0,0 +1,272 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import tools.jackson.core.StreamReadFeature;
import tools.jackson.databind.json.JsonMapper;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.function.SingletonSupplier;
/**
* Check configuration metadata for inconsistencies. The available checks are:
* <ul>
* <li>Metadata element should be sorted alphabetically: {@link #analyzeSort(Report)}</li>
* <li>Property must have a description:
* {@link #analyzePropertyDescription(Report, List)}</li>
* </ul>
*
* @author Stephane Nicoll
*/
class ConfigurationPropertiesAnalyzer {
private final Collection<File> sources;
private final SingletonSupplier<JsonMapper> jsonMapperSupplier;
ConfigurationPropertiesAnalyzer(Collection<File> sources) {
if (sources.isEmpty()) {
throw new IllegalArgumentException("At least one source should be provided");
}
this.sources = sources;
this.jsonMapperSupplier = SingletonSupplier
.of(() -> JsonMapper.builder().enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION).build());
}
void analyzeSort(Report report) {
for (File source : this.sources) {
report.registerAnalysis(source, analyzeSort(source));
}
}
private Analysis analyzeSort(File source) {
Map<String, Object> json = readJsonContent(source);
Analysis analysis = new Analysis("Metadata element order:");
analyzeMetadataElementsSort("groups", json, analysis);
analyzeMetadataElementsSort("properties", json, analysis);
analyzeMetadataElementsSort("hints", json, analysis);
return analysis;
}
@SuppressWarnings("unchecked")
private void analyzeMetadataElementsSort(String key, Map<String, Object> json, Analysis analysis) {
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.getOrDefault(key, Collections.emptyList());
List<String> names = groups.stream().map((group) -> (String) group.get("name")).toList();
List<String> sortedNames = names.stream().sorted().toList();
for (int i = 0; i < names.size(); i++) {
String actual = names.get(i);
String expected = sortedNames.get(i);
if (!actual.equals(expected)) {
analysis.addItem("Wrong order at $." + key + "[" + i + "].name - expected '" + expected
+ "' but found '" + actual + "'");
}
}
}
void analyzePropertyDescription(Report report, List<String> exclusions) {
for (File source : this.sources) {
report.registerAnalysis(source, analyzePropertyDescription(source, exclusions));
}
}
@SuppressWarnings("unchecked")
private Analysis analyzePropertyDescription(File source, List<String> exclusions) {
Map<String, Object> json = readJsonContent(source);
Analysis analysis = new Analysis("The following properties have no description:");
List<Map<String, Object>> properties = (List<Map<String, Object>>) json.get("properties");
for (Map<String, Object> property : properties) {
String name = (String) property.get("name");
if (!isDeprecated(property) && !isDescribed(property) && !isExcluded(exclusions, name)) {
analysis.addItem(name);
}
}
return analysis;
}
private boolean isExcluded(List<String> exclusions, String propertyName) {
for (String exclusion : exclusions) {
if (propertyName.equals(exclusion)) {
return true;
}
if (exclusion.endsWith(".*")) {
if (propertyName.startsWith(exclusion.substring(0, exclusion.length() - 2))) {
return true;
}
}
}
return false;
}
private boolean isDeprecated(Map<String, Object> property) {
return property.get("deprecation") != null;
}
private boolean isDescribed(Map<String, Object> property) {
return property.get("description") != null;
}
void analyzeDeprecationSince(Report report) throws IOException {
for (File source : this.sources) {
report.registerAnalysis(source, analyzeDeprecationSince(source));
}
}
@SuppressWarnings("unchecked")
private Analysis analyzeDeprecationSince(File source) throws IOException {
Analysis analysis = new Analysis("The following properties are deprecated without a 'since' version:");
Map<String, Object> json = readJsonContent(source);
List<Map<String, Object>> properties = (List<Map<String, Object>>) json.get("properties");
properties.stream().filter((property) -> property.containsKey("deprecation")).forEach((property) -> {
Map<String, Object> deprecation = (Map<String, Object>) property.get("deprecation");
if (!deprecation.containsKey("since")) {
analysis.addItem(property.get("name").toString());
}
});
return analysis;
}
@SuppressWarnings("unchecked")
private Map<String, Object> readJsonContent(File source) {
return this.jsonMapperSupplier.obtain().readValue(source, Map.class);
}
private static <T> void writeAll(PrintWriter writer, Iterable<T> elements, Consumer<T> itemWriter) {
Iterator<T> it = elements.iterator();
while (it.hasNext()) {
itemWriter.accept(it.next());
if (it.hasNext()) {
writer.println();
}
}
}
static class Report {
private final File baseDirectory;
private final MultiValueMap<File, Analysis> analyses = new LinkedMultiValueMap<>();
Report(File baseDirectory) {
this.baseDirectory = baseDirectory;
}
void registerAnalysis(File path, Analysis analysis) {
this.analyses.add(path, analysis);
}
boolean hasProblems() {
return this.analyses.values()
.stream()
.anyMatch((candidates) -> candidates.stream().anyMatch(Analysis::hasProblems));
}
List<Analysis> getAnalyses(File source) {
return this.analyses.getOrDefault(source, Collections.emptyList());
}
/**
* Write this report to the given {@code file}.
* @param file the file to write the report to
*/
void write(File file) throws IOException {
Files.writeString(file.toPath(), createContent(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
}
private String createContent() {
if (this.analyses.isEmpty()) {
return "No problems found.";
}
StringWriter out = new StringWriter();
try (PrintWriter writer = new PrintWriter(out)) {
writeAll(writer, this.analyses.entrySet(), (entry) -> {
writer.println(this.baseDirectory.toPath().relativize(entry.getKey().toPath()));
boolean hasProblems = entry.getValue().stream().anyMatch(Analysis::hasProblems);
if (hasProblems) {
writeAll(writer, entry.getValue(), (analysis) -> analysis.createDetails(writer));
}
else {
writer.println("No problems found.");
}
});
}
return out.toString();
}
}
static class Analysis {
private final String header;
private final List<String> items;
Analysis(String header) {
this.header = header;
this.items = new ArrayList<>();
}
void addItem(String item) {
this.items.add(item);
}
boolean hasProblems() {
return !this.items.isEmpty();
}
List<String> getItems() {
return this.items;
}
void createDetails(PrintWriter writer) {
writer.println(this.header);
if (this.items.isEmpty()) {
writer.println("No problems found.");
}
else {
for (String item : this.items) {
writer.println("\t- " + item);
}
}
}
@Override
public String toString() {
StringWriter out = new StringWriter();
PrintWriter writer = new PrintWriter(out);
createDetails(writer);
return out.toString();
}
}
}

View File

@ -123,7 +123,7 @@ public abstract class DocumentConfigurationProperties extends DefaultTask {
private void jsonPrefixes(Config config) {
config.accept("spring.jackson");
config.accept("spring.gson");
config.accept("spring.kotlin.serialization");
config.accept("spring.kotlinx.serialization.json");
}
private void dataPrefixes(Config config) {

View File

@ -142,7 +142,7 @@ class PluginXmlParser {
return new Iterator<>() {
private int index = 0;
private int index;
@Override
public boolean hasNext() {

View File

@ -19,9 +19,11 @@ package org.springframework.boot.build.architecture;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@ -42,6 +44,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;
import org.springframework.boot.build.architecture.annotations.TestDeprecatedConfigurationProperty;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileSystemUtils;
@ -340,6 +343,16 @@ class ArchitectureCheckTests {
build(gradleBuild, Task.CHECK_ARCHITECTURE_TEST);
}
@Test
void whenDeprecatedConfigurationPropertyIsMissingSinceShouldFailAndWriteReport() throws IOException {
prepareTask(Task.CHECK_ARCHITECTURE_MAIN, "configurationproperties", "annotations");
GradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)
.withDeprecatedConfigurationPropertyAnnotation(TestDeprecatedConfigurationProperty.class.getName());
buildAndFail(gradleBuild, Task.CHECK_ARCHITECTURE_MAIN,
"should include a non-empty 'since' attribute of @DeprecatedConfigurationProperty",
"DeprecatedConfigurationPropertySince.getProperty");
}
private void prepareTask(Task task, String... sourceDirectories) throws IOException {
for (String sourceDirectory : sourceDirectories) {
FileSystemUtils.copyRecursively(
@ -372,7 +385,12 @@ class ArchitectureCheckTests {
try {
BuildResult buildResult = gradleBuild.buildAndFail(task.toString());
assertThat(buildResult.taskPaths(TaskOutcome.FAILED)).as(buildResult.getOutput()).contains(":" + task);
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).contains(messages);
try {
assertThat(task.getFailureReport(gradleBuild.getProjectDir())).contains(messages);
}
catch (NoSuchFileException ex) {
throw new AssertionError("Expected failure report not found\n" + buildResult.getOutput());
}
}
catch (UnexpectedBuildSuccess ex) {
throw new AssertionError("Expected build to fail but it succeeded\n" + ex.getBuildResult().getOutput(), ex);
@ -405,7 +423,7 @@ class ArchitectureCheckTests {
@Override
public String toString() {
return "checkArchitecture" + StringUtils.capitalize(this.sourceSetName);
return "checkArchitecture" + StringUtils.capitalize(this.sourceSetName) + "Java";
}
}
@ -436,9 +454,18 @@ class ArchitectureCheckTests {
return this;
}
GradleBuild withConditionalOnClassAnnotation(String annotationName) {
GradleBuild withConditionalOnClassAnnotation(String annotationClass) {
for (Task task : Task.values()) {
configureTask(task, (configuration) -> configuration.withConditionalOnClassAnnotation(annotationName));
configureTask(task, (configuration) -> configuration
.withAnnotation(ArchitectureCheck.CONDITIONAL_ON_CLASS, annotationClass));
}
return this;
}
GradleBuild withDeprecatedConfigurationPropertyAnnotation(String annotationClass) {
for (Task task : Task.values()) {
configureTask(task, (configuration) -> configuration
.withAnnotation(ArchitectureCheck.DEPRECATED_CONFIGURATION_PROPERTY, annotationClass));
}
return this;
}
@ -498,18 +525,18 @@ class ArchitectureCheckTests {
for (String dependency : this.dependencies) {
buildFile.append("\n implementation ").append(StringUtils.quote(dependency));
}
buildFile.append("}\n");
buildFile.append("\n}\n\n");
}
this.taskConfigurations.forEach((task, configuration) -> {
buildFile.append(task).append(" {");
if (configuration.conditionalOnClassAnnotation() != null) {
buildFile.append("\n conditionalOnClassAnnotation = ")
.append(StringUtils.quote(configuration.conditionalOnClassAnnotation()));
}
if (configuration.prohibitObjectsRequireNonNull() != null) {
buildFile.append("\n prohibitObjectsRequireNonNull = ")
.append(configuration.prohibitObjectsRequireNonNull());
}
if (configuration.annotations() != null && !configuration.annotations().isEmpty()) {
buildFile.append("\n annotationClasses = ")
.append(toGroovyMapString(configuration.annotations()));
}
buildFile.append("\n}\n");
});
NullMarkedExtension nullMarkedExtension = this.nullMarkedExtension;
@ -536,6 +563,13 @@ class ArchitectureCheckTests {
.withPluginClasspath();
}
static String toGroovyMapString(Map<String, String> map) {
return map.entrySet()
.stream()
.map((entry) -> "'" + entry.getKey() + "' : '" + entry.getValue() + "'")
.collect(Collectors.joining(", ", "[", "]"));
}
private record NullMarkedExtension(Boolean enabled, Set<String> ignoredPackages) {
private NullMarkedExtension withEnabled(Boolean enabled) {
@ -548,15 +582,24 @@ class ArchitectureCheckTests {
}
private record TaskConfiguration(Boolean prohibitObjectsRequireNonNull, String conditionalOnClassAnnotation) {
private record TaskConfiguration(Boolean prohibitObjectsRequireNonNull, Map<String, String> annotations) {
private TaskConfiguration withConditionalOnClassAnnotation(String annotationName) {
return new TaskConfiguration(this.prohibitObjectsRequireNonNull, annotationName);
public TaskConfiguration {
if (annotations == null) {
annotations = new HashMap<>();
}
}
private TaskConfiguration withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {
return new TaskConfiguration(prohibitObjectsRequireNonNull, this.conditionalOnClassAnnotation);
return new TaskConfiguration(prohibitObjectsRequireNonNull, this.annotations);
}
private TaskConfiguration withAnnotation(String name, String annotationClass) {
Map<String, String> map = new HashMap<>(this.annotations);
map.put(name, annotationClass);
return new TaskConfiguration(this.prohibitObjectsRequireNonNull, map);
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.architecture.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* {@code @DeprecatedConfigurationProperty} analogue for architecture checks.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestDeprecatedConfigurationProperty {
/**
* The reason for the deprecation.
* @return the deprecation reason
*/
String reason() default "";
/**
* The field that should be used instead (if any).
* @return the replacement field
*/
String replacement() default "";
/**
* The version in which the property became deprecated.
* @return the version
*/
String since() default "";
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.architecture.configurationproperties;
import org.springframework.boot.build.architecture.annotations.TestDeprecatedConfigurationProperty;
public class DeprecatedConfigurationPropertySince {
private String property;
@TestDeprecatedConfigurationProperty(reason = "no longer used")
@Deprecated
public String getProperty() {
return this.property;
}
public void setProperty(String property) {
this.property = property;
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.build.context.properties;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Analysis;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link ConfigurationPropertiesAnalyzer}.
*
* @author Stephane Nicoll
*/
class ConfigurationPropertiesAnalyzerTests {
@Test
void createAnalyzerWithNoSource() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ConfigurationPropertiesAnalyzer(Collections.emptyList()))
.withMessage("At least one source should be provided");
}
@Test
void analyzeSortWithAlphabeticalOrder(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "abc"}, {"name": "def"}, {"name": "xyz"}
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeSort(report);
assertThat(report.hasProblems()).isFalse();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));
}
@Test
void analyzeSortWithViolations(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "def"}, {"name": "abc"}, {"name": "xyz"}
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeSort(report);
assertThat(report.hasProblems()).isTrue();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies((analysis) -> assertThat(analysis.getItems()).containsExactly(
"Wrong order at $.properties[0].name - expected 'abc' but found 'def'",
"Wrong order at $.properties[1].name - expected 'def' but found 'abc'"));
}
@Test
void analyzePropertyDescription(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "abc", "description": "This is abc." },
{ "name": "def", "description": "This is def." },
{ "name": "xyz", "description": "This is xyz." }
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzePropertyDescription(report, List.of());
assertThat(report.hasProblems()).isFalse();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));
}
@Test
void analyzePropertyDescriptionWithMissingDescription(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "abc", "description": "This is abc." },
{ "name": "def" },
{ "name": "xyz", "description": "This is xyz." }
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzePropertyDescription(report, List.of());
assertThat(report.hasProblems()).isTrue();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).containsExactly("def")));
}
@Test
void analyzeDeprecatedPropertyWithMissingSince(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{
"name": "abc",
"description": "This is abc.",
"deprecation": { "reason": "abc reason", "since": "3.0.0" }
},
{ "name": "def", "description": "This is def." },
{
"name": "xyz",
"description": "This is xyz.",
"deprecation": { "reason": "xyz reason" }
}
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeDeprecationSince(report);
assertThat(report.hasProblems()).isTrue();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).containsExactly("xyz")));
}
@Test
void writeEmptyReport(@TempDir File tempDir) throws IOException {
assertThat(writeToFile(tempDir, new Report(tempDir))).hasContent("No problems found.");
}
@Test
void writeReportWithNoProblemsFound(@TempDir File tempDir) throws IOException {
Report report = new Report(tempDir);
File first = new File(tempDir, "metadata-1.json");
report.registerAnalysis(first, new Analysis("Check for things:"));
File second = new File(tempDir, "metadata-2.json");
report.registerAnalysis(second, new Analysis("Check for other things:"));
assertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines("""
metadata-1.json
No problems found.
metadata-2.json
No problems found.
""");
}
@Test
void writeReportWithOneProblem(@TempDir File tempDir) throws IOException {
Report report = new Report(tempDir);
File metadata = new File(tempDir, "metadata-1.json");
Analysis analysis = new Analysis("Check for things:");
analysis.addItem("Should not be deprecated");
report.registerAnalysis(metadata, analysis);
report.registerAnalysis(metadata, new Analysis("Check for other things:"));
assertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines("""
metadata-1.json
Check for things:
- Should not be deprecated
Check for other things:
No problems found.
""");
}
@Test
void writeReportWithSeveralProblems(@TempDir File tempDir) throws IOException {
Report report = new Report(tempDir);
File metadata = new File(tempDir, "metadata-1.json");
Analysis firstAnalysis = new Analysis("Check for things:");
firstAnalysis.addItem("Should not be deprecated");
firstAnalysis.addItem("Should not be public");
report.registerAnalysis(metadata, firstAnalysis);
Analysis secondAnalysis = new Analysis("Check for other things:");
secondAnalysis.addItem("Field 'this' not expected");
report.registerAnalysis(metadata, secondAnalysis);
assertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines("""
metadata-1.json
Check for things:
- Should not be deprecated
- Should not be public
Check for other things:
- Field 'this' not expected
""");
}
private File writeToFile(File directory, Report report) throws IOException {
File file = new File(directory, "report.txt");
report.write(file);
return file;
}
}

View File

@ -142,14 +142,14 @@ class SpringRepositoriesExtensionTests {
@Test
void mavenRepositoriesWhenConditionMatches() {
SpringRepositoriesExtension extension = createExtension("0.0.0-SNAPSHOT", "oss");
extension.mavenRepositories(true);
extension.mavenRepositoriesFor("1.2.3-SNAPSHOT");
assertThat(this.repositories).hasSize(1);
}
@Test
void mavenRepositoriesWhenConditionDoesNotMatch() {
SpringRepositoriesExtension extension = createExtension("0.0.0-SNAPSHOT", "oss");
extension.mavenRepositories(false);
extension.mavenRepositoriesFor("1.2.3");
assertThat(this.repositories).isEmpty();
}
@ -252,7 +252,7 @@ class SpringRepositoriesExtensionTests {
void mavenRepositories();
void mavenRepositories(boolean condition);
void mavenRepositoriesFor(Object version);
void mavenRepositoriesExcludingBootGroup();

View File

@ -71,7 +71,6 @@ final class ApiVersions {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ApiVersions other = (ApiVersions) obj;
return Arrays.equals(this.apiVersions, other.apiVersions);
}

View File

@ -106,17 +106,25 @@ public class Builder {
this.log.start(request);
validateBindings(request.getBindings());
PullPolicy pullPolicy = request.getPullPolicy();
ImageFetcher imageFetcher = new ImageFetcher(this.dockerConfiguration.builderRegistryAuthentication(),
pullPolicy, request.getImagePlatform());
Image builderImage = imageFetcher.fetchImage(ImageType.BUILDER, request.getBuilder());
ImagePlatform platform = request.getImagePlatform();
boolean specifiedPlatform = request.getImagePlatform() != null;
DockerRegistryAuthentication registryAuthentication = this.dockerConfiguration.builderRegistryAuthentication();
ImageFetcher imageFetcher = new ImageFetcher(registryAuthentication, pullPolicy);
Image builderImage = imageFetcher.fetchImage(ImageType.BUILDER, request.getBuilder(), platform);
BuilderMetadata builderMetadata = BuilderMetadata.fromImage(builderImage);
request = withRunImageIfNeeded(request, builderMetadata);
Assert.state(request.getRunImage() != null, "'request.getRunImage()' must not be null");
Image runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage());
platform = (platform != null) ? platform : ImagePlatform.from(builderImage);
Image runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage(), platform);
if (specifiedPlatform && runImage.getPrimaryDigest() != null) {
request = request.withRunImage(request.getRunImage().withDigest(runImage.getPrimaryDigest()));
runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage(), platform);
}
assertStackIdsMatch(runImage, builderImage);
BuildOwner buildOwner = BuildOwner.fromEnv(builderImage.getConfig().getEnv());
BuildpackLayersMetadata buildpackLayersMetadata = BuildpackLayersMetadata.fromImage(builderImage);
Buildpacks buildpacks = getBuildpacks(request, imageFetcher, builderMetadata, buildpackLayersMetadata);
Buildpacks buildpacks = getBuildpacks(request, imageFetcher, platform, builderMetadata,
buildpackLayersMetadata);
EphemeralBuilder ephemeralBuilder = new EphemeralBuilder(buildOwner, builderImage, request.getName(),
builderMetadata, request.getCreator(), request.getEnv(), buildpacks);
executeLifecycle(request, ephemeralBuilder);
@ -160,9 +168,9 @@ public class Builder {
}
}
private Buildpacks getBuildpacks(BuildRequest request, ImageFetcher imageFetcher, BuilderMetadata builderMetadata,
BuildpackLayersMetadata buildpackLayersMetadata) {
BuildpackResolverContext resolverContext = new BuilderResolverContext(imageFetcher, builderMetadata,
private Buildpacks getBuildpacks(BuildRequest request, ImageFetcher imageFetcher, ImagePlatform platform,
BuilderMetadata builderMetadata, BuildpackLayersMetadata buildpackLayersMetadata) {
BuildpackResolverContext resolverContext = new BuilderResolverContext(imageFetcher, platform, builderMetadata,
buildpackLayersMetadata);
return BuildpackResolvers.resolveAll(resolverContext, request.getBuildpacks());
}
@ -225,49 +233,74 @@ public class Builder {
private final PullPolicy pullPolicy;
private @Nullable ImagePlatform defaultPlatform;
ImageFetcher(@Nullable DockerRegistryAuthentication registryAuthentication, PullPolicy pullPolicy,
@Nullable ImagePlatform platform) {
ImageFetcher(@Nullable DockerRegistryAuthentication registryAuthentication, PullPolicy pullPolicy) {
this.registryAuthentication = registryAuthentication;
this.pullPolicy = pullPolicy;
this.defaultPlatform = platform;
}
Image fetchImage(ImageType type, ImageReference reference) throws IOException {
Image fetchImage(ImageType type, ImageReference reference, @Nullable ImagePlatform platform)
throws IOException {
Assert.notNull(type, "'type' must not be null");
Assert.notNull(reference, "'reference' must not be null");
if (this.pullPolicy == PullPolicy.ALWAYS) {
return checkPlatformMismatch(pullImage(reference, type), reference);
return pullImageAndCheckForPlatformMismatch(type, reference, platform);
}
try {
return checkPlatformMismatch(Builder.this.docker.image().inspect(reference), reference);
Image image = Builder.this.docker.image().inspect(reference, platform);
return checkPlatformMismatch(image, reference, platform);
}
catch (DockerEngineException ex) {
if (this.pullPolicy == PullPolicy.IF_NOT_PRESENT && ex.getStatusCode() == 404) {
return checkPlatformMismatch(pullImage(reference, type), reference);
return pullImageAndCheckForPlatformMismatch(type, reference, platform);
}
throw ex;
}
}
private Image pullImage(ImageReference reference, ImageType imageType) throws IOException {
TotalProgressPullListener listener = new TotalProgressPullListener(
Builder.this.log.pullingImage(reference, this.defaultPlatform, imageType));
String authHeader = authHeader(this.registryAuthentication, reference);
Image image = Builder.this.docker.image().pull(reference, this.defaultPlatform, listener, authHeader);
Builder.this.log.pulledImage(image, imageType);
if (this.defaultPlatform == null) {
this.defaultPlatform = ImagePlatform.from(image);
private Image pullImageAndCheckForPlatformMismatch(ImageType type, ImageReference reference,
@Nullable ImagePlatform platform) throws IOException {
try {
Image image = pullImage(reference, type, platform);
return checkPlatformMismatch(image, reference, platform);
}
catch (DockerEngineException ex) {
// Try to throw our own exception for consistent log output. Matching
// on the message is a little brittle, but it doesn't matter too much
// if it fails as the original exception is still enough to stop the build
if (platform != null && ex.getMessage() != null
&& ex.getMessage().contains("does not provide the specified platform")) {
throwAsPlatformMismatchException(type, reference, platform, ex);
}
throw ex;
}
}
private void throwAsPlatformMismatchException(ImageType type, ImageReference reference, ImagePlatform platform,
@Nullable Throwable cause) throws IOException {
try {
Image image = pullImage(reference, type, null);
throw new PlatformMismatchException(reference, platform, ImagePlatform.from(image), cause);
}
catch (DockerEngineException ex) {
}
}
private Image pullImage(ImageReference reference, ImageType imageType, @Nullable ImagePlatform platform)
throws IOException {
TotalProgressPullListener listener = new TotalProgressPullListener(
Builder.this.log.pullingImage(reference, platform, imageType));
String authHeader = authHeader(this.registryAuthentication, reference);
Image image = Builder.this.docker.image().pull(reference, platform, listener, authHeader);
Builder.this.log.pulledImage(image, imageType);
return image;
}
private Image checkPlatformMismatch(Image image, ImageReference imageReference) {
if (this.defaultPlatform != null) {
ImagePlatform imagePlatform = ImagePlatform.from(image);
if (!imagePlatform.equals(this.defaultPlatform)) {
throw new PlatformMismatchException(imageReference, this.defaultPlatform, imagePlatform);
private Image checkPlatformMismatch(Image image, ImageReference reference,
@Nullable ImagePlatform requestedPlatform) {
if (requestedPlatform != null) {
ImagePlatform actualPlatform = ImagePlatform.from(image);
if (!actualPlatform.equals(requestedPlatform)) {
throw new PlatformMismatchException(reference, requestedPlatform, actualPlatform, null);
}
}
return image;
@ -278,9 +311,9 @@ public class Builder {
private static final class PlatformMismatchException extends RuntimeException {
private PlatformMismatchException(ImageReference imageReference, ImagePlatform requestedPlatform,
ImagePlatform actualPlatform) {
ImagePlatform actualPlatform, @Nullable Throwable cause) {
super("Image platform mismatch detected. The configured platform '%s' is not supported by the image '%s'. Requested platform '%s' but got '%s'"
.formatted(requestedPlatform, imageReference, requestedPlatform, actualPlatform));
.formatted(requestedPlatform, imageReference, requestedPlatform, actualPlatform), cause);
}
}
@ -326,13 +359,16 @@ public class Builder {
private final ImageFetcher imageFetcher;
private final ImagePlatform platform;
private final BuilderMetadata builderMetadata;
private final BuildpackLayersMetadata buildpackLayersMetadata;
BuilderResolverContext(ImageFetcher imageFetcher, BuilderMetadata builderMetadata,
BuilderResolverContext(ImageFetcher imageFetcher, ImagePlatform platform, BuilderMetadata builderMetadata,
BuildpackLayersMetadata buildpackLayersMetadata) {
this.imageFetcher = imageFetcher;
this.platform = platform;
this.builderMetadata = builderMetadata;
this.buildpackLayersMetadata = buildpackLayersMetadata;
}
@ -349,13 +385,13 @@ public class Builder {
@Override
public Image fetchImage(ImageReference reference, ImageType imageType) throws IOException {
return this.imageFetcher.fetchImage(imageType, reference);
return this.imageFetcher.fetchImage(imageType, reference, this.platform);
}
@Override
public void exportImageLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
throws IOException {
Builder.this.docker.image().exportLayers(reference, exports);
Builder.this.docker.image().exportLayers(reference, this.platform, exports);
}
}

View File

@ -16,6 +16,7 @@
package org.springframework.boot.buildpack.platform.docker;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -30,10 +31,13 @@ import org.springframework.util.Assert;
* @author Scott Frederick
* @since 4.0.0
*/
public final class ApiVersion {
public final class ApiVersion implements Comparable<ApiVersion> {
private static final Pattern PATTERN = Pattern.compile("^v?(\\d+)\\.(\\d*)$");
private static final Comparator<ApiVersion> COMPARATOR = Comparator.comparing(ApiVersion::getMajor)
.thenComparing(ApiVersion::getMinor);
private final int major;
private final int minor;
@ -138,4 +142,9 @@ public final class ApiVersion {
return new ApiVersion(major, minor);
}
@Override
public int compareTo(ApiVersion other) {
return COMPARATOR.compare(this, other);
}
}

View File

@ -62,12 +62,10 @@ public class DockerApi {
private static final List<String> FORCE_PARAMS = Collections.unmodifiableList(Arrays.asList("force", "1"));
static final ApiVersion API_VERSION = ApiVersion.of(1, 24);
static final ApiVersion PLATFORM_API_VERSION = ApiVersion.of(1, 41);
static final ApiVersion UNKNOWN_API_VERSION = ApiVersion.of(0, 0);
static final ApiVersion PREFERRED_API_VERSION = ApiVersion.of(1, 50);
static final String API_VERSION_HEADER_NAME = "API-Version";
private final HttpTransport http;
@ -126,18 +124,38 @@ public class DockerApi {
return this.jsonStream;
}
URI buildPlatformJsonUrl(Feature feature, @Nullable ImagePlatform platform, String path) {
if (platform != null && getApiVersion().supports(feature.minimumVersion())) {
return buildUrl(feature, path, "platform", platform.toJson());
}
return buildUrl(path);
}
private URI buildUrl(String path, @Nullable Collection<?> params) {
return buildUrl(API_VERSION, path, (params != null) ? params.toArray() : null);
return buildUrl(Feature.BASELINE, path, (params != null) ? params.toArray() : null);
}
private URI buildUrl(String path, Object... params) {
return buildUrl(API_VERSION, path, params);
return buildUrl(Feature.BASELINE, path, params);
}
private URI buildUrl(ApiVersion apiVersion, String path, Object @Nullable ... params) {
verifyApiVersion(apiVersion);
URI buildUrl(Feature feature, String path, Object @Nullable ... params) {
ApiVersion version = getApiVersion();
if (version.equals(UNKNOWN_API_VERSION) || (version.compareTo(PREFERRED_API_VERSION) >= 0
&& version.compareTo(feature.minimumVersion()) >= 0)) {
return buildVersionedUrl(PREFERRED_API_VERSION, path, params);
}
if (version.compareTo(feature.minimumVersion()) >= 0) {
return buildVersionedUrl(version, path, params);
}
throw new IllegalStateException(
"Docker API version must be at least %s to support this feature, but current API version is %s"
.formatted(feature.minimumVersion(), version));
}
private URI buildVersionedUrl(ApiVersion version, String path, Object @Nullable ... params) {
try {
URIBuilder builder = new URIBuilder("/v" + apiVersion + path);
URIBuilder builder = new URIBuilder("/v" + version + path);
if (params != null) {
int param = 0;
while (param < params.length) {
@ -151,13 +169,6 @@ public class DockerApi {
}
}
private void verifyApiVersion(ApiVersion minimumVersion) {
ApiVersion actualVersion = getApiVersion();
Assert.state(actualVersion.equals(UNKNOWN_API_VERSION) || actualVersion.supports(minimumVersion),
() -> "Docker API version must be at least " + minimumVersion
+ " to support this feature, but current API version is " + actualVersion);
}
private ApiVersion getApiVersion() {
ApiVersion apiVersion = this.apiVersion;
if (apiVersion == null) {
@ -225,9 +236,8 @@ public class DockerApi {
UpdateListener<PullImageUpdateEvent> listener, @Nullable String registryAuth) throws IOException {
Assert.notNull(reference, "'reference' must not be null");
Assert.notNull(listener, "'listener' must not be null");
URI createUri = (platform != null)
? buildUrl(PLATFORM_API_VERSION, "/images/create", "fromImage", reference, "platform", platform)
: buildUrl("/images/create", "fromImage", reference);
URI createUri = (platform != null) ? buildUrl(Feature.PLATFORM_IMAGE_PULL, "/images/create", "fromImage",
reference, "platform", platform) : buildUrl("/images/create", "fromImage", reference);
DigestCaptureUpdateListener digestCapture = new DigestCaptureUpdateListener();
listener.onStart();
try {
@ -237,7 +247,7 @@ public class DockerApi {
listener.onUpdate(event);
});
}
return inspect((platform != null) ? PLATFORM_API_VERSION : API_VERSION, reference);
return inspect(reference, platform);
}
finally {
listener.onFinish();
@ -309,9 +319,24 @@ public class DockerApi {
*/
public void exportLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
throws IOException {
exportLayers(reference, null, exports);
}
/**
* Export the layers of an image as {@link TarArchive TarArchives}.
* @param reference the reference to export
* @param platform the platform (os/architecture/variant) of the image to export.
* Ignored on older versions of Docker.
* @param exports a consumer to receive the layers (contents can only be accessed
* during the callback)
* @throws IOException on IO error
* @since 3.4.12
*/
public void exportLayers(ImageReference reference, @Nullable ImagePlatform platform,
IOBiConsumer<String, TarArchive> exports) throws IOException {
Assert.notNull(reference, "'reference' must not be null");
Assert.notNull(exports, "'exports' must not be null");
URI uri = buildUrl("/images/" + reference + "/get");
URI uri = buildPlatformJsonUrl(Feature.PLATFORM_IMAGE_EXPORT, platform, "/images/" + reference + "/get");
try (Response response = http().get(uri)) {
try (ExportedImageTar exportedImageTar = new ExportedImageTar(reference, response.getContent())) {
exportedImageTar.exportLayers(exports);
@ -339,13 +364,25 @@ public class DockerApi {
* @throws IOException on IO error
*/
public Image inspect(ImageReference reference) throws IOException {
return inspect(API_VERSION, reference);
return inspect(reference, null);
}
private Image inspect(ApiVersion apiVersion, ImageReference reference) throws IOException {
/**
* Inspect an image.
* @param reference the image reference
* @param platform the platform (os/architecture/variant) of the image to inspect.
* Ignored on older versions of Docker.
* @return the image from the local repository
* @throws IOException on IO error
* @since 3.4.12
*/
public Image inspect(ImageReference reference, @Nullable ImagePlatform platform) throws IOException {
// The Docker documentation is incomplete but platform parameters
// are supported since 1.49 (see https://github.com/moby/moby/pull/49586)
Assert.notNull(reference, "'reference' must not be null");
URI imageUri = buildUrl(apiVersion, "/images/" + reference + "/json");
try (Response response = http().get(imageUri)) {
URI inspectUrl = buildPlatformJsonUrl(Feature.PLATFORM_IMAGE_INSPECT, platform,
"/images/" + reference + "/json");
try (Response response = http().get(inspectUrl)) {
return Image.of(response.getContent());
}
}
@ -393,7 +430,7 @@ public class DockerApi {
private ContainerReference createContainer(ContainerConfig config, @Nullable ImagePlatform platform)
throws IOException {
URI createUri = (platform != null)
? buildUrl(PLATFORM_API_VERSION, "/containers/create", "platform", platform)
? buildUrl(Feature.PLATFORM_CONTAINER_CREATE, "/containers/create", "platform", platform)
: buildUrl("/containers/create");
try (Response response = http().post(createUri, "application/json", config::writeTo)) {
return ContainerReference
@ -598,4 +635,28 @@ public class DockerApi {
}
enum Feature {
BASELINE(ApiVersion.of(1, 24)),
PLATFORM_IMAGE_PULL(ApiVersion.of(1, 41)),
PLATFORM_CONTAINER_CREATE(ApiVersion.of(1, 41)),
PLATFORM_IMAGE_INSPECT(ApiVersion.of(1, 49)),
PLATFORM_IMAGE_EXPORT(ApiVersion.of(1, 48));
private final ApiVersion minimumVersion;
Feature(ApiVersion minimumVersion) {
this.minimumVersion = minimumVersion;
}
ApiVersion minimumVersion() {
return this.minimumVersion;
}
}
}

View File

@ -19,9 +19,12 @@ package org.springframework.boot.buildpack.platform.docker;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import tools.jackson.databind.node.ObjectNode;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.json.SharedJsonMapper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A platform specification for a Docker image.
@ -102,4 +105,20 @@ public class ImagePlatform {
return new ImagePlatform(image.getOs(), image.getArchitecture(), image.getVariant());
}
/**
* Return a JSON-encoded representation of this platform.
* @return the JSON string
*/
public String toJson() {
ObjectNode json = SharedJsonMapper.get().createObjectNode();
json.put("os", this.os);
if (StringUtils.hasText(this.architecture)) {
json.put("architecture", this.architecture);
}
if (StringUtils.hasText(this.variant)) {
json.put("variant", this.variant);
}
return json.toString();
}
}

View File

@ -22,11 +22,13 @@ import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import tools.jackson.databind.JsonNode;
import org.springframework.boot.buildpack.platform.json.MappedObject;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
@ -52,6 +54,8 @@ public class Image extends MappedObject {
private final @Nullable String created;
private final @Nullable Descriptor descriptor;
Image(JsonNode node) {
super(node, MethodHandles.lookup());
this.digests = childrenAt("/RepoDigests", JsonNode::asString);
@ -61,6 +65,9 @@ public class Image extends MappedObject {
this.architecture = valueAt("/Architecture", String.class);
this.variant = valueAt("/Variant", String.class);
this.created = valueAt("/Created", String.class);
JsonNode descriptorNode = getNode().path("Descriptor");
this.descriptor = (descriptorNode.isMissingNode() || descriptorNode.isNull()) ? null
: new Descriptor(descriptorNode);
}
private List<LayerId> extractLayers(String @Nullable [] layers) {
@ -126,6 +133,35 @@ public class Image extends MappedObject {
return this.created;
}
/**
* Return the descriptor for this image as reported by Docker Engine inspect.
* @return the image descriptor or {@code null}
*/
public @Nullable Descriptor getDescriptor() {
return this.descriptor;
}
/**
* Return the primary digest of the image or {@code null}. Checks the
* {@code Descriptor.digest} first, falling back to {@code RepoDigest}.
* @return the primary digest or {@code null}
* @since 3.4.12
*/
public @Nullable String getPrimaryDigest() {
if (this.descriptor != null && StringUtils.hasText(this.descriptor.getDigest())) {
return this.descriptor.getDigest();
}
if (!CollectionUtils.isEmpty(this.digests)) {
try {
String digest = this.digests.get(0);
return (digest != null) ? ImageReference.of(digest).getDigest() : null;
}
catch (RuntimeException ex) {
}
}
return null;
}
/**
* Create a new {@link Image} instance from the specified JSON content.
* @param content the JSON content
@ -136,4 +172,24 @@ public class Image extends MappedObject {
return of(content, Image::new);
}
/**
* Descriptor details as reported in the {@code Docker inspect} response.
*
* @since 3.4.12
*/
public final class Descriptor extends MappedObject {
private final String digest;
Descriptor(JsonNode node) {
super(node, MethodHandles.lookup());
this.digest = Objects.requireNonNull(valueAt("/digest", String.class));
}
public String getDigest() {
return this.digest;
}
}
}

View File

@ -78,6 +78,9 @@ class BuilderTests {
private static final ImageReference BASE_CNB = ImageReference.of("docker.io/cloudfoundry/run:base-cnb");
private static final ImageReference PLATFORM_CNB = ImageReference
.of("docker.io/cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad");
@Test
@SuppressWarnings("NullAway") // Test null check
void createWhenLogIsNullThrowsException() {
@ -278,8 +281,8 @@ class BuilderTests {
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))
.willAnswer(withPulledImage(runImage));
given(docker.image().inspect(eq(DEFAULT_BUILDER))).willReturn(builderImage);
given(docker.image().inspect(eq(BASE_CNB))).willReturn(runImage);
given(docker.image().inspect(eq(DEFAULT_BUILDER), any())).willReturn(builderImage);
given(docker.image().inspect(eq(BASE_CNB), any())).willReturn(runImage);
Builder builder = new Builder(BuildLog.to(out), docker, null);
BuildRequest request = getTestRequest().withPullPolicy(PullPolicy.NEVER);
builder.build(request);
@ -291,7 +294,7 @@ class BuilderTests {
assertThat(tag).isNotNull();
then(docker.image()).should().remove(tag, true);
then(docker.image()).should(never()).pull(any(), any(), any());
then(docker.image()).should(times(2)).inspect(any());
then(docker.image()).should(times(2)).inspect(any(), any());
}
@Test
@ -330,11 +333,11 @@ class BuilderTests {
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))
.willAnswer(withPulledImage(runImage));
given(docker.image().inspect(eq(DEFAULT_BUILDER)))
given(docker.image().inspect(eq(DEFAULT_BUILDER), any()))
.willThrow(new TestDockerEngineException("docker://localhost/", new URI("example"), 404, "NOT FOUND", null,
null, null))
.willReturn(builderImage);
given(docker.image().inspect(eq(BASE_CNB)))
given(docker.image().inspect(eq(BASE_CNB), any()))
.willThrow(new TestDockerEngineException("docker://localhost/", new URI("example"), 404, "NOT FOUND", null,
null, null))
.willReturn(runImage);
@ -348,7 +351,7 @@ class BuilderTests {
ImageReference tag = archive.getValue().getTag();
assertThat(tag).isNotNull();
then(docker.image()).should().remove(tag, true);
then(docker.image()).should(times(2)).inspect(any());
then(docker.image()).should(times(2)).inspect(any(), any());
then(docker.image()).should(times(2)).pull(any(), any(), any(), isNull());
}
@ -425,6 +428,8 @@ class BuilderTests {
given(docker.image().pull(eq(DEFAULT_BUILDER), eq(platform), any(), isNull()))
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(BASE_CNB), eq(platform), any(), isNull())).willAnswer(withPulledImage(runImage));
given(docker.image().pull(eq(PLATFORM_CNB), eq(platform), any(), isNull()))
.willAnswer(withPulledImage(runImage));
Builder builder = new Builder(BuildLog.to(out), docker, null);
BuildRequest request = getTestRequest().withImagePlatform("linux/arm64/v1");
builder.build(request);
@ -433,6 +438,7 @@ class BuilderTests {
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
then(docker.image()).should().pull(eq(DEFAULT_BUILDER), eq(platform), any(), isNull());
then(docker.image()).should().pull(eq(BASE_CNB), eq(platform), any(), isNull());
then(docker.image()).should().pull(eq(PLATFORM_CNB), eq(platform), any(), isNull());
then(docker.image()).should().load(archive.capture(), any());
ImageReference tag = archive.getValue().getTag();
assertThat(tag).isNotNull();

View File

@ -111,6 +111,17 @@ class ApiVersionTests {
assertThat(v12a).isEqualTo(v12a).isEqualTo(v12b).isNotEqualTo(v13);
}
@Test
void compareTo() {
assertThat(ApiVersion.of(0, 0).compareTo(ApiVersion.of(0, 0))).isZero();
assertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(0, 1))).isZero();
assertThat(ApiVersion.of(1, 0).compareTo(ApiVersion.of(1, 0))).isZero();
assertThat(ApiVersion.of(0, 0).compareTo(ApiVersion.of(0, 1))).isLessThan(0);
assertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(0, 0))).isGreaterThan(0);
assertThat(ApiVersion.of(1, 0).compareTo(ApiVersion.of(0, 1))).isGreaterThan(0);
assertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(1, 0))).isLessThan(0);
}
private boolean supports(String v1, String v2) {
return ApiVersion.parse(v1).supports(ApiVersion.parse(v2));
}

View File

@ -23,6 +23,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
@ -41,6 +43,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.Feature;
import org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.SystemApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;
@ -86,22 +89,21 @@ import static org.mockito.Mockito.times;
@ExtendWith({ MockitoExtension.class, OutputCaptureExtension.class })
class DockerApiTests {
private static final String API_URL = "/v" + DockerApi.API_VERSION;
private static final String PLATFORM_API_URL = "/v" + DockerApi.PLATFORM_API_VERSION;
private static final String API_URL = "/v" + DockerApi.PREFERRED_API_VERSION;
public static final String PING_URL = "/_ping";
private static final String IMAGES_URL = API_URL + "/images";
private static final String PLATFORM_IMAGES_URL = PLATFORM_API_URL + "/images";
private static final String CONTAINERS_URL = API_URL + "/containers";
private static final String PLATFORM_CONTAINERS_URL = PLATFORM_API_URL + "/containers";
private static final String VOLUMES_URL = API_URL + "/volumes";
private static final ImagePlatform LINUX_ARM64_PLATFORM = ImagePlatform.of("linux/arm64/v1");
private static final String ENCODED_LINUX_ARM64_PLATFORM_JSON = URLEncoder.encode(LINUX_ARM64_PLATFORM.toJson(),
StandardCharsets.UTF_8);
@Mock
@SuppressWarnings("NullAway.Init")
private HttpTransport http;
@ -168,6 +170,52 @@ class DockerApiTests {
assertThat(api).isNotNull();
}
@Test
void buildUrlWhenUnknownVersionUsesPreferredVersion() throws Exception {
setVersion("0.0");
assertThat(this.dockerApi.buildUrl(Feature.BASELINE, "/test"))
.isEqualTo(URI.create("/v" + DockerApi.PREFERRED_API_VERSION + "/test"));
}
@Test
void buildUrlWhenVersionIsGreaterThanPreferredUsesPreferred() throws Exception {
setVersion("1000.0");
assertThat(this.dockerApi.buildUrl(Feature.BASELINE, "/test"))
.isEqualTo(URI.create("/v" + DockerApi.PREFERRED_API_VERSION + "/test"));
}
@Test
void buildUrlWhenVersionIsEqualToPreferredUsesPreferred() throws Exception {
setVersion(DockerApi.PREFERRED_API_VERSION.toString());
assertThat(this.dockerApi.buildUrl(Feature.BASELINE, "/test"))
.isEqualTo(URI.create("/v" + DockerApi.PREFERRED_API_VERSION + "/test"));
}
@Test
void buildUrlWhenVersionIsLessThanPreferredAndGreaterThanMinimumUsesVersionVersion() throws Exception {
setVersion("1.48");
assertThat(this.dockerApi.buildUrl(Feature.BASELINE, "/test")).isEqualTo(URI.create("/v1.48/test"));
}
@Test
void buildUrlWhenVersionIsLessThanPreferredAndEqualToMinimumUsesVersionVersion() throws Exception {
setVersion(Feature.BASELINE.minimumVersion().toString());
assertThat(this.dockerApi.buildUrl(Feature.BASELINE, "/test")).isEqualTo(URI.create("/v1.24/test"));
}
@Test
void buildUrlWhenVersionIsLessThanMinimumThrowsException() throws Exception {
setVersion("1.23");
assertThatIllegalStateException().isThrownBy(() -> this.dockerApi.buildUrl(Feature.BASELINE, "/test"))
.withMessage("Docker API version must be at least 1.24 "
+ "to support this feature, but current API version is 1.23");
}
private void setVersion(String version) throws IOException, URISyntaxException {
given(http().head(eq(new URI(PING_URL))))
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, version)));
}
@Nested
class ImageDockerApiTests {
@ -242,15 +290,14 @@ class DockerApiTests {
@Test
void pullWithPlatformPullsImageAndProducesEvents() throws Exception {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
URI createUri = new URI(PLATFORM_IMAGES_URL
+ "/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase&platform=linux%2Farm64%2Fv1");
URI imageUri = new URI(PLATFORM_IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/json");
given(http().head(eq(new URI(PING_URL))))
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.41")));
URI createUri = new URI(
"/v1.49/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase&platform=linux%2Farm64%2Fv1");
URI imageUri = new URI("/v1.49/images/gcr.io/paketo-buildpacks/builder:base/json?platform="
+ ENCODED_LINUX_ARM64_PLATFORM_JSON);
setVersion("1.49");
given(http().post(eq(createUri), isNull())).willReturn(responseOf("pull-stream.json"));
given(http().get(imageUri)).willReturn(responseOf("type/image.json"));
Image image = this.api.pull(reference, platform, this.pullListener);
Image image = this.api.pull(reference, LINUX_ARM64_PLATFORM, this.pullListener);
assertThat(image.getLayers()).hasSize(46);
InOrder ordered = inOrder(this.pullListener);
ordered.verify(this.pullListener).onStart();
@ -262,8 +309,7 @@ class DockerApiTests {
void pullWithPlatformAndInsufficientApiVersionThrowsException() throws Exception {
ImageReference reference = ImageReference.of("gcr.io/paketo-buildpacks/builder:base");
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
given(http().head(eq(new URI(PING_URL)))).willReturn(
responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, DockerApi.API_VERSION)));
setVersion("1.24");
assertThatIllegalStateException().isThrownBy(() -> this.api.pull(reference, platform, this.pullListener))
.withMessageContaining("must be at least 1.41")
.withMessageContaining("current API version is 1.24");
@ -400,6 +446,30 @@ class DockerApiTests {
URI imageUri = new URI(IMAGES_URL + "/docker.io/paketobuildpacks/builder:base/json");
given(http().get(imageUri)).willReturn(responseOf("type/image.json"));
Image image = this.api.inspect(reference);
assertThat(image.getArchitecture()).isEqualTo("amd64");
assertThat(image.getLayers()).hasSize(46);
}
@Test
void inspectWithPlatformWhenSupportedVersionInspectImage() throws Exception {
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
URI imageUri = new URI("/v1.49/images/docker.io/paketobuildpacks/builder:base/json?platform="
+ ENCODED_LINUX_ARM64_PLATFORM_JSON);
setVersion("1.49");
given(http().get(imageUri)).willReturn(responseOf("type/image-platform.json"));
Image image = this.api.inspect(reference, LINUX_ARM64_PLATFORM);
assertThat(image.getArchitecture()).isEqualTo("arm64");
assertThat(image.getLayers()).hasSize(2);
}
@Test
void inspectWithPlatformWhenOldVersionInspectImage() throws Exception {
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
URI imageUri = new URI("/v1.48/images/docker.io/paketobuildpacks/builder:base/json");
setVersion("1.48");
given(http().get(imageUri)).willReturn(responseOf("type/image.json"));
Image image = this.api.inspect(reference, LINUX_ARM64_PLATFORM);
assertThat(image.getArchitecture()).isEqualTo("amd64");
assertThat(image.getLayers()).hasSize(46);
}
@ -431,6 +501,65 @@ class DockerApiTests {
.containsExactly("/cnb/stack.toml");
}
@Test
void exportLayersExportsLayerTarsWithPlatformWhenSupportedVersion() throws Exception {
setVersion("1.48");
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
URI exportUri = new URI("/v1.48/images/docker.io/paketobuildpacks/builder:base/get?platform="
+ ENCODED_LINUX_ARM64_PLATFORM_JSON);
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export.tar"));
MultiValueMap<String, String> contents = new LinkedMultiValueMap<>();
this.api.exportLayers(reference, LINUX_ARM64_PLATFORM, (name, archive) -> {
ByteArrayOutputStream out = new ByteArrayOutputStream();
archive.writeTo(out);
try (TarArchiveInputStream in = new TarArchiveInputStream(
new ByteArrayInputStream(out.toByteArray()))) {
TarArchiveEntry entry = in.getNextEntry();
while (entry != null) {
contents.add(name, entry.getName());
entry = in.getNextEntry();
}
}
});
assertThat(contents).hasSize(3)
.containsKeys("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar",
"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar",
"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar");
assertThat(contents.get("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar"))
.containsExactly("/cnb/order.toml");
assertThat(contents.get("74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar"))
.containsExactly("/cnb/stack.toml");
}
@Test
void exportLayersExportsLayerTarsWithPlatformWhenOldVersionInspectImage() throws Exception {
setVersion("1.47");
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
URI exportUri = new URI("/v1.47/images/docker.io/paketobuildpacks/builder:base/get");
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export.tar"));
MultiValueMap<String, String> contents = new LinkedMultiValueMap<>();
this.api.exportLayers(reference, LINUX_ARM64_PLATFORM, (name, archive) -> {
ByteArrayOutputStream out = new ByteArrayOutputStream();
archive.writeTo(out);
try (TarArchiveInputStream in = new TarArchiveInputStream(
new ByteArrayInputStream(out.toByteArray()))) {
TarArchiveEntry entry = in.getNextEntry();
while (entry != null) {
contents.add(name, entry.getName());
entry = in.getNextEntry();
}
}
});
assertThat(contents).hasSize(3)
.containsKeys("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar",
"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar",
"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar");
assertThat(contents.get("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar"))
.containsExactly("/cnb/order.toml");
assertThat(contents.get("74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar"))
.containsExactly("/cnb/stack.toml");
}
@Test
void exportLayersWithSymlinksExportsLayerTars() throws Exception {
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
@ -564,7 +693,19 @@ class DockerApiTests {
@Test
void createWithPlatformCreatesContainer() throws Exception {
createWithPlatform("1.41");
ImageReference imageReference = ImageReference.of("ubuntu:bionic");
ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash"));
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
setVersion("1.41");
URI createUri = new URI("/v1.41/containers/create?platform=linux%2Farm64%2Fv1");
given(http().post(eq(createUri), eq("application/json"), any()))
.willReturn(responseOf("create-container-response.json"));
ContainerReference containerReference = this.api.create(config, platform);
assertThat(containerReference).hasToString("e90e34656806");
then(http()).should().post(any(), any(), this.writer.capture());
ByteArrayOutputStream out = new ByteArrayOutputStream();
this.writer.getValue().accept(out);
assertThat(out.toByteArray()).hasSize(config.toString().length());
}
@Test
@ -576,11 +717,7 @@ class DockerApiTests {
ImageReference imageReference = ImageReference.of("ubuntu:bionic");
ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash"));
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
if (apiVersion != null) {
given(http().head(eq(new URI(PING_URL))))
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, apiVersion)));
}
URI createUri = new URI(PLATFORM_CONTAINERS_URL + "/create?platform=linux%2Farm64%2Fv1");
URI createUri = new URI(CONTAINERS_URL + "/create?platform=linux%2Farm64%2Fv1");
given(http().post(eq(createUri), eq("application/json"), any()))
.willReturn(responseOf("create-container-response.json"));
ContainerReference containerReference = this.api.create(config, platform);
@ -596,8 +733,7 @@ class DockerApiTests {
ImageReference imageReference = ImageReference.of("ubuntu:bionic");
ContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand("/bin/bash"));
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
given(http().head(eq(new URI(PING_URL))))
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.24")));
setVersion("1.24");
assertThatIllegalStateException().isThrownBy(() -> this.api.create(config, platform))
.withMessageContaining("must be at least 1.41")
.withMessageContaining("current API version is 1.24");

View File

@ -64,6 +64,20 @@ class ImagePlatformTests extends AbstractJsonTests {
assertThat(platform.toString()).isEqualTo("linux/amd64/v1");
}
@Test
void toJsonString() {
ImagePlatform platform = ImagePlatform.of("linux/amd64/v1");
assertThat(platform.toJson()).isEqualTo("""
{"os":"linux","architecture":"amd64","variant":"v1"}""");
}
@Test
void toJsonStringWhenOnlyOs() {
ImagePlatform platform = ImagePlatform.of("linux");
assertThat(platform.toJson()).isEqualTo("""
{"os":"linux"}""");
}
private Image getImage() throws IOException {
return Image.of(getContent("type/image.json"));
}

View File

@ -76,7 +76,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForDockerDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForDockerDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@ -99,7 +99,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForLegacyDockerDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForLegacyDockerDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("index.docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@ -121,7 +121,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForCustomDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForCustomDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("my-registry.example.com/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@ -143,7 +143,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForCustomDomainWithLegacyFormat(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForCustomDomainWithLegacyFormat(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("my-registry.example.com/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@ -160,7 +160,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenEmptyConfigDirectoryReturnsFallback(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenEmptyConfigDirectoryReturnsFallback(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference, DockerRegistryAuthentication.EMPTY_USER);

View File

@ -23,6 +23,7 @@ import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.buildpack.platform.docker.type.Image.Descriptor;
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
import static org.assertj.core.api.Assertions.assertThat;
@ -98,6 +99,35 @@ class ImageTests extends AbstractJsonTests {
assertThat(image.getCreated()).isEqualTo("2019-10-30T19:34:56.296666503Z");
}
@Test
void getDescriptorReturnsDescriptor() throws Exception {
Image image = getImage();
Descriptor descriptor = image.getDescriptor();
assertThat(descriptor).isNotNull();
assertThat(descriptor.getDigest())
.isEqualTo("sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96");
}
@Test
void getPrimaryDigestWhenHasDescriptor() throws Exception {
Image image = getImage();
assertThat(image.getPrimaryDigest())
.isEqualTo("sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96");
}
@Test
void getPrimaryDigestWhenNoDescriptor() throws Exception {
Image image = Image.of(getContent("image-no-descriptor.json"));
assertThat(image.getPrimaryDigest())
.isEqualTo("sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba");
}
@Test
void getPrimaryDigestWhenNoDigest() throws Exception {
Image image = Image.of(getContent("image-no-digest.json"));
assertThat(image.getPrimaryDigest()).isNull();
}
private Image getImage() throws IOException {
return Image.of(getContent("image.json"));
}

View File

@ -31,7 +31,7 @@ class FileDescriptorTests {
private final int sourceHandle = 123;
private int closedHandle = 0;
private int closedHandle;
@Test
void acquireReturnsHandle() throws Exception {

View File

@ -0,0 +1,25 @@
{
"Id": "sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba",
"RepoTags": [
"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1"
],
"RepoDigests": [
"ghcr.io/spring-io/spring-boot-cnb-test-builder@sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba"
],
"Parent": "",
"Comment": "",
"DockerVersion": "",
"Author": "",
"Config": null,
"Architecture": "",
"Os": "",
"Size": 166797518,
"GraphDriver": {
"Data": null,
"Name": "overlayfs"
},
"RootFS": {},
"Metadata": {
"LastTagTime": "2025-04-10T22:41:27.520294922Z"
}
}

View File

@ -0,0 +1,22 @@
{
"Id": "sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba",
"RepoTags": [
"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1"
],
"Parent": "",
"Comment": "",
"DockerVersion": "",
"Author": "",
"Config": null,
"Architecture": "",
"Os": "",
"Size": 166797518,
"GraphDriver": {
"Data": null,
"Name": "overlayfs"
},
"RootFS": {},
"Metadata": {
"LastTagTime": "2025-04-10T22:41:27.520294922Z"
}
}

View File

@ -1,5 +1,27 @@
{
"Id": "sha256:9b450bffdb05bcf660d464d0bfdf344ee6ca38e9b8de4f408c8080b0c9319349",
"Descriptor": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96",
"size": 424,
"urls": [
"https://example.com"
],
"annotations": {
"com.docker.official-images.bashbrew.arch": "amd64",
"org.opencontainers.image.version": "24.04"
},
"data": null,
"platform": {
"architecture": "arm",
"os": "windows",
"os.version": "10.0.19041.1165",
"os.features": [
],
"variant": "v7"
},
"artifactType": null
},
"RepoTags": [
"paketo-buildpacks/cnb:latest"
],

View File

@ -16,6 +16,7 @@
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
<module name="io.spring.javaformat.checkstyle.check.SpringDeprecatedCheck" />
<module name="io.spring.javaformat.checkstyle.check.SpringJUnit5Check" />
<module name="ExplicitInitialization" />
<module
name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
<property name="regexp" value="true" />

View File

@ -46,7 +46,7 @@ architectureCheck {
def dependenciesOf(String version) {
if (version.startsWith("4.0")) {
def modules = [
return [
"spring-boot",
"spring-boot-activemq",
"spring-boot-actuator",
@ -105,6 +105,8 @@ def dependenciesOf(String version) {
"spring-boot-micrometer-metrics-test",
"spring-boot-micrometer-observation",
"spring-boot-micrometer-tracing",
"spring-boot-micrometer-tracing-brave",
"spring-boot-micrometer-tracing-opentelemetry",
"spring-boot-micrometer-tracing-test",
"spring-boot-mongodb",
"spring-boot-mustache",
@ -148,13 +150,6 @@ def dependenciesOf(String version) {
"spring-boot-webservices-test",
"spring-boot-zipkin"
]
if (version.equals("4.0.0-RC2")) {
modules += [
"spring-boot-micrometer-tracing-brave",
"spring-boot-micrometer-tracing-opentelemetry"
]
}
return modules
}
return [
"spring-boot",

View File

@ -211,8 +211,9 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
ClassLoader classLoader = (this.beanClassLoader != null) ? this.beanClassLoader : getClass().getClassLoader();
for (String exclusion : exclusions) {
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
if (ClassUtils.isPresent(exclusion, classLoader) && !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}

View File

@ -472,13 +472,19 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
}
private List<String> getPrimaryBeans(Map<String, @Nullable BeanDefinition> beanDefinitions) {
return getMatchingBeans(beanDefinitions,
(beanDefinition) -> beanDefinition != null && beanDefinition.isPrimary());
return getMatchingBeans(beanDefinitions, this::isPrimary);
}
private boolean isPrimary(@Nullable BeanDefinition beanDefinition) {
return (beanDefinition != null) && beanDefinition.isPrimary();
}
private List<String> getNonFallbackBeans(Map<String, @Nullable BeanDefinition> beanDefinitions) {
return getMatchingBeans(beanDefinitions,
Predicate.not((beanDefinition) -> beanDefinition != null && beanDefinition.isFallback()));
return getMatchingBeans(beanDefinitions, this::isNotFallback);
}
private boolean isNotFallback(@Nullable BeanDefinition beanDefinition) {
return (beanDefinition == null) || !beanDefinition.isFallback();
}
private List<String> getMatchingBeans(Map<String, @Nullable BeanDefinition> beanDefinitions,

View File

@ -76,13 +76,13 @@ public class MessageSourceProperties {
* Whether to always apply the MessageFormat rules, parsing even messages without
* arguments.
*/
private boolean alwaysUseMessageFormat = false;
private boolean alwaysUseMessageFormat;
/**
* Whether to use the message code as the default message instead of throwing a
* "NoSuchMessageException". Recommended during development only.
*/
private boolean useCodeAsDefaultMessage = false;
private boolean useCodeAsDefaultMessage;
public List<String> getBasename() {
return this.basename;

View File

@ -33,12 +33,12 @@ public class JmxProperties {
/**
* Expose Spring's management beans to the JMX domain.
*/
private boolean enabled = false;
private boolean enabled;
/**
* Whether unique runtime object names should be ensured.
*/
private boolean uniqueNames = false;
private boolean uniqueNames;
/**
* MBeanServer bean name.

View File

@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.http.CacheControl;
@ -50,6 +51,9 @@ public class WebProperties {
private final Resources resources = new Resources();
@NestedConfigurationProperty
private final ErrorProperties error = new ErrorProperties();
public @Nullable Locale getLocale() {
return this.locale;
}
@ -66,6 +70,10 @@ public class WebProperties {
this.localeResolver = localeResolver;
}
public ErrorProperties getError() {
return this.error;
}
public Resources getResources() {
return this.resources;
}
@ -101,7 +109,7 @@ public class WebProperties {
*/
private boolean addMappings = true;
private boolean customized = false;
private boolean customized;
private final Chain chain = new Chain();
@ -151,7 +159,7 @@ public class WebProperties {
*/
public static class Chain {
boolean customized = false;
boolean customized;
/**
* Whether to enable the Spring Resource Handling chain. By default, disabled
@ -169,7 +177,7 @@ public class WebProperties {
* brotli). Checks for a resource name with the '.gz' or '.br' file
* extensions.
*/
private boolean compressed = false;
private boolean compressed;
private final Strategy strategy = new Strategy();
@ -246,7 +254,7 @@ public class WebProperties {
*/
public static class Content {
private boolean customized = false;
private boolean customized;
/**
* Whether to enable the content Version Strategy.
@ -287,7 +295,7 @@ public class WebProperties {
*/
public static class Fixed {
private boolean customized = false;
private boolean customized;
/**
* Whether to enable the fixed Version Strategy.
@ -346,7 +354,7 @@ public class WebProperties {
*/
public static class Cache {
private boolean customized = false;
private boolean customized;
/**
* Cache period for the resources served by the resource handler. If a
@ -398,7 +406,7 @@ public class WebProperties {
*/
public static class Cachecontrol {
private boolean customized = false;
private boolean customized;
/**
* Maximum time the response should be cached, in seconds if no duration

View File

@ -36,7 +36,8 @@
"description": "Resource reference to a generated git info properties file.",
"deprecation": {
"replacement": "spring.info.git.location",
"level": "error"
"level": "error",
"since": "1.4.0"
}
},
{
@ -58,7 +59,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.add-mappings",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -66,7 +68,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.cache-private",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -74,7 +77,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.cache-public",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -82,7 +86,8 @@
"type": "java.time.Duration",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.max-age",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -90,7 +95,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.must-revalidate",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -98,7 +104,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.no-cache",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -106,7 +113,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.no-store",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -114,7 +122,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.no-transform",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -122,7 +131,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.proxy-revalidate",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -130,7 +140,8 @@
"type": "java.time.Duration",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.s-max-age",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -138,7 +149,8 @@
"type": "java.time.Duration",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.stale-if-error",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -146,7 +158,8 @@
"type": "java.time.Duration",
"deprecation": {
"replacement": "spring.web.resources.cache.cachecontrol.stale-while-revalidate",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -154,7 +167,8 @@
"type": "java.time.Duration",
"deprecation": {
"replacement": "spring.web.resources.cache.period",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -162,7 +176,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.cache.use-last-modified",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -170,7 +185,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.cache",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -178,7 +194,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.compressed",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -186,7 +203,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.enabled",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -194,14 +212,16 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.compressed",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
"name": "spring.resources.chain.html-application-cache",
"type": "java.lang.Boolean",
"deprecation": {
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -209,7 +229,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.strategy.content.enabled",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -217,7 +238,8 @@
"type": "java.lang.String[]",
"deprecation": {
"replacement": "spring.web.resources.chain.strategy.content.paths",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -225,7 +247,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"replacement": "spring.web.resources.chain.strategy.fixed.enabled",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -233,7 +256,8 @@
"type": "java.lang.String[]",
"deprecation": {
"replacement": "spring.web.resources.chain.strategy.fixed.paths",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -241,7 +265,8 @@
"type": "java.lang.String",
"deprecation": {
"replacement": "spring.web.resources.chain.strategy.fixed.version",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{
@ -249,7 +274,8 @@
"type": "java.lang.String[]",
"deprecation": {
"replacement": "spring.web.resources.static-locations",
"level": "error"
"level": "error",
"since": "2.4.0"
}
},
{

View File

@ -1,3 +1,6 @@
defaults.spring.template.provider.cache=false
defaults.spring.web.error.include-binding-errors=always
defaults.spring.web.error.include-message=always
defaults.spring.web.error.include-stacktrace=always
defaults.spring.web.resources.cache.period=0
defaults.spring.web.resources.chain.cache=false

View File

@ -195,6 +195,16 @@ class ConditionalOnSingleCandidateTests {
});
}
@Test
void singleCandidateDoesNotMatchWhenMultipleRegisteredAsSingletonCandidates() {
this.contextRunner.withInitializer((context) -> {
context.getBeanFactory().registerSingleton("alpha", "alpha");
context.getBeanFactory().registerSingleton("bravo", "bravo");
})
.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean("consumer"));
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(String.class)
static class OnBeanSingleCandidateConfiguration {

View File

@ -130,7 +130,7 @@ class JmxAutoConfigurationTests {
@ManagedResource
public static class Counter {
private int counter = 0;
private int counter;
@ManagedAttribute
public int get() {

View File

@ -336,7 +336,7 @@ class FileWatcherTests {
private CountDownLatch latch = new CountDownLatch(1);
volatile boolean changed = false;
volatile boolean changed;
@Override
public void run() {

View File

@ -16,6 +16,7 @@
plugins {
id "java-library"
id "org.springframework.boot.configuration-metadata"
id "org.springframework.boot.deployed"
id "org.springframework.boot.optional-dependencies"
}

View File

@ -9,8 +9,9 @@
{
"name": "spring.test.observability.auto-configure",
"deprecation": {
"level": "error",
"reason": "Superseded by 'spring.test.metrics.export' and 'spring.test.tracing.export'.",
"level": "error"
"since": "4.0.0"
}
},
{

View File

@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class SpringBootTestWebEnvironmentMockTests {
@Value("${value}")
private int value = 0;
private int value;
@Autowired
private WebApplicationContext context;

View File

@ -144,7 +144,7 @@ class ImportTestcontainersTests {
@ImportTestcontainers
static class NullContainer {
static @Nullable PostgreSQLContainer container = null;
static @Nullable PostgreSQLContainer container;
}

View File

@ -63,7 +63,7 @@ class SpringApplicationShutdownHook implements Runnable {
private final AtomicBoolean shutdownHookAdded = new AtomicBoolean();
private volatile boolean shutdownHookAdditionEnabled = false;
private volatile boolean shutdownHookAdditionEnabled;
private boolean inProgress;

View File

@ -48,7 +48,7 @@ class SpringBootExceptionHandler implements UncaughtExceptionHandler {
private final List<Throwable> loggedExceptions = new ArrayList<>();
private int exitCode = 0;
private int exitCode;
SpringBootExceptionHandler(@Nullable UncaughtExceptionHandler parent) {
this.parent = parent;

View File

@ -193,7 +193,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private boolean parseArgs = true;
private @Nullable LogLevel springBootLogging = null;
private @Nullable LogLevel springBootLogging;
@Override
public boolean supportsEventType(ResolvableType resolvableType) {

View File

@ -373,7 +373,7 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
private final @Nullable ConfigurationPropertyName[] names;
private int index = 0;
private int index;
ConfigurationPropertyNamesIterator(@Nullable ConfigurationPropertyName[] names) {
this.names = names;

View File

@ -87,7 +87,7 @@ public final class CorrelationIdFormatter {
* @return a formatted correlation id
*/
public String format(UnaryOperator<@Nullable String> resolver) {
StringBuilder result = new StringBuilder();
StringBuilder result = new StringBuilder(this.blank.length());
formatTo(resolver, result);
return result.toString();
}

View File

@ -39,7 +39,7 @@ public final class RetryPolicySettings {
/**
* Default number of retry attempts.
*/
public static final long DEFAULT_MAX_ATTEMPTS = RetryPolicy.Builder.DEFAULT_MAX_ATTEMPTS;
public static final long DEFAULT_MAX_RETRIES = RetryPolicy.Builder.DEFAULT_MAX_RETRIES;
/**
* Default initial delay.
@ -62,7 +62,7 @@ public final class RetryPolicySettings {
private @Nullable Predicate<Throwable> exceptionPredicate;
private Long maxAttempts = DEFAULT_MAX_ATTEMPTS;
private Long maxRetries = DEFAULT_MAX_RETRIES;
private Duration delay = DEFAULT_DELAY;
@ -84,7 +84,7 @@ public final class RetryPolicySettings {
map.from(this::getExceptionIncludes).to(builder::includes);
map.from(this::getExceptionExcludes).to(builder::excludes);
map.from(this::getExceptionPredicate).to(builder::predicate);
map.from(this::getMaxAttempts).to(builder::maxAttempts);
map.from(this::getMaxRetries).to(builder::maxRetries);
map.from(this::getDelay).to(builder::delay);
map.from(this::getJitter).to(builder::jitter);
map.from(this::getMultiplier).to(builder::multiplier);
@ -153,18 +153,19 @@ public final class RetryPolicySettings {
/**
* Return the maximum number of retry attempts.
* @return the maximum number of retry attempts
* @see #DEFAULT_MAX_ATTEMPTS
* @see #DEFAULT_MAX_RETRIES
*/
public Long getMaxAttempts() {
return this.maxAttempts;
public Long getMaxRetries() {
return this.maxRetries;
}
/**
* Specify the maximum number of retry attempts.
* @param maxAttempts the max attempts (must be equal or greater than zero)
* @param maxRetries the maximum number of retry attempts (must be equal or greater
* than zero)
*/
public void setMaxAttempts(Long maxAttempts) {
this.maxAttempts = maxAttempts;
public void setMaxRetries(Long maxRetries) {
this.maxRetries = maxRetries;
}
/**

View File

@ -53,14 +53,15 @@ class SpringFactoriesEnvironmentPostProcessorsFactory implements EnvironmentPost
argumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext);
List<Object> postProcessors = new ArrayList<>();
postProcessors.addAll(this.loader.load(EnvironmentPostProcessor.class, argumentResolver));
postProcessors.addAll(loadDeprecatedPostProcessors());
postProcessors.addAll(loadDeprecatedPostProcessors(argumentResolver));
AnnotationAwareOrderComparator.sort(postProcessors);
return postProcessors.stream().map(Adapter::apply).collect(Collectors.toCollection(ArrayList::new));
}
@SuppressWarnings("removal")
private List<org.springframework.boot.env.EnvironmentPostProcessor> loadDeprecatedPostProcessors() {
return this.loader.load(org.springframework.boot.env.EnvironmentPostProcessor.class);
private List<org.springframework.boot.env.EnvironmentPostProcessor> loadDeprecatedPostProcessors(
ArgumentResolver argumentResolver) {
return this.loader.load(org.springframework.boot.env.EnvironmentPostProcessor.class, argumentResolver);
}
@SuppressWarnings("removal")

View File

@ -40,6 +40,7 @@ import org.springframework.util.StringUtils;
* {@link SystemEnvironmentOrigin} for every system environment property.
*
* @author Madhura Bhave
* @author Phillip Webb
* @since 4.0.0
*/
public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@ -53,10 +54,14 @@ public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
postProcessEnvironment(environment, application.getEnvironmentPrefix());
}
private void postProcessEnvironment(ConfigurableEnvironment environment, @Nullable String environmentPrefix) {
String sourceName = StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
PropertySource<?> propertySource = environment.getPropertySources().get(sourceName);
if (propertySource != null) {
replacePropertySource(environment, sourceName, propertySource, application.getEnvironmentPrefix());
replacePropertySource(environment, sourceName, propertySource, environmentPrefix);
}
}
@ -78,6 +83,23 @@ public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements
this.order = order;
}
/**
* Post-process the given {@link ConfigurableEnvironment} by copying appropriate
* settings from a parent {@link ConfigurableEnvironment}.
* @param environment the environment to post-process
* @param parentEnvironment the parent environment
* @since 3.4.12
*/
public static void postProcessEnvironment(ConfigurableEnvironment environment,
ConfigurableEnvironment parentEnvironment) {
PropertySource<?> parentSystemEnvironmentPropertySource = parentEnvironment.getPropertySources()
.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
if (parentSystemEnvironmentPropertySource instanceof OriginAwareSystemEnvironmentPropertySource parentOriginAwareSystemEnvironmentPropertySource) {
new SystemEnvironmentPropertySourceEnvironmentPostProcessor().postProcessEnvironment(environment,
parentOriginAwareSystemEnvironmentPropertySource.getPrefix());
}
}
/**
* {@link SystemEnvironmentPropertySource} that also tracks {@link Origin}.
*/

View File

@ -48,7 +48,8 @@
"description": "Log file name (for instance, `myapp.log`). Names can be an exact location or relative to the current directory.",
"deprecation": {
"replacement": "logging.file.name",
"level": "error"
"level": "error",
"since": "2.2.0"
}
},
{
@ -58,7 +59,8 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": false,
"deprecation": {
"replacement": "logging.logback.rollingpolicy.clean-history-on-start"
"replacement": "logging.logback.rollingpolicy.clean-history-on-start",
"since": "2.4.0"
}
},
{
@ -68,7 +70,8 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": 7,
"deprecation": {
"replacement": "logging.logback.rollingpolicy.max-history"
"replacement": "logging.logback.rollingpolicy.max-history",
"since": "2.4.0"
}
},
{
@ -78,7 +81,8 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "10MB",
"deprecation": {
"replacement": "logging.logback.rollingpolicy.max-file-size"
"replacement": "logging.logback.rollingpolicy.max-file-size",
"since": "2.4.0"
}
},
{
@ -100,7 +104,8 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "0B",
"deprecation": {
"replacement": "logging.logback.rollingpolicy.total-size-cap"
"replacement": "logging.logback.rollingpolicy.total-size-cap",
"since": "2.4.0"
}
},
{
@ -175,7 +180,8 @@
"description": "Location of the log file. For instance, `/var/log`.",
"deprecation": {
"replacement": "logging.file.path",
"level": "error"
"level": "error",
"since": "2.2.0"
}
},
{
@ -217,7 +223,8 @@
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz",
"deprecation": {
"replacement": "logging.logback.rollingpolicy.file-name-pattern"
"replacement": "logging.logback.rollingpolicy.file-name-pattern",
"since": "2.4.0"
}
},
{
@ -355,7 +362,8 @@
"description": "Application index.",
"deprecation": {
"level": "error",
"reason": "Application context ids are now unique by default."
"reason": "Application context ids are now unique by default.",
"since": "2.0.0"
}
},
{
@ -380,7 +388,8 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -388,7 +397,8 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -396,7 +406,8 @@
"type": "java.lang.Boolean",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -404,7 +415,8 @@
"type": "org.springframework.core.io.Resource",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -412,7 +424,8 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -420,7 +433,8 @@
"type": "org.springframework.boot.ImageBanner$PixelMode",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -428,7 +442,8 @@
"type": "java.lang.Integer",
"deprecation": {
"level": "error",
"reason": "Support for image banners has been removed."
"reason": "Support for image banners has been removed.",
"since": "3.0.0"
}
},
{
@ -547,7 +562,8 @@
"description": "Display the banner when the application runs.",
"defaultValue": true,
"deprecation": {
"replacement": "spring.main.banner-mode"
"replacement": "spring.main.banner-mode",
"since": "1.3.0"
}
},
{
@ -568,7 +584,8 @@
"sourceType": "org.springframework.boot.SpringApplication",
"description": "Run the application in a web environment (auto-detected by default).",
"deprecation": {
"replacement": "spring.main.web-application-type"
"replacement": "spring.main.web-application-type",
"since": "2.0.0"
}
},
{

View File

@ -22,7 +22,7 @@ import org.jspecify.annotations.Nullable;
class TestLog4J2LoggingSystem extends Log4J2LoggingSystem {
private boolean disableSelfInitialization = false;
private boolean disableSelfInitialization;
TestLog4J2LoggingSystem(String contextName) {
// Tests add resources to the thread context classloader

View File

@ -128,7 +128,7 @@ class RetryPolicySettingsTests {
@Test
void createRetryPolicyWithCustomAttributes() {
RetryPolicySettings settings = new RetryPolicySettings();
settings.setMaxAttempts(10L);
settings.setMaxRetries(10L);
settings.setDelay(Duration.ofSeconds(2));
settings.setJitter(Duration.ofMillis(500));
settings.setMultiplier(2.0);

View File

@ -111,4 +111,19 @@ class SystemEnvironmentPropertySourceEnvironmentPostProcessorTests {
assertThat(replaced.getPrefix()).isEqualTo("my");
}
@Test
void postProcessWithParentEnvironmentShouldApplyPrefix() {
SpringApplication application = new SpringApplication();
application.setEnvironmentPrefix("my");
new SystemEnvironmentPropertySourceEnvironmentPostProcessor().postProcessEnvironment(this.environment,
application);
StandardEnvironment child = new StandardEnvironment();
SystemEnvironmentPropertySourceEnvironmentPostProcessor.postProcessEnvironment(child, this.environment);
OriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) child
.getPropertySources()
.get("systemEnvironment");
assertThat(replaced).isNotNull();
assertThat(replaced.getPrefix()).isEqualTo("my");
}
}

View File

@ -150,6 +150,9 @@ dependencies {
implementation("io.micrometer:micrometer-tracing")
implementation("io.micrometer:micrometer-registry-graphite")
implementation("io.micrometer:micrometer-registry-jmx")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
implementation("io.opentelemetry:opentelemetry-sdk-metrics")
implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0")
implementation("io.projectreactor.netty:reactor-netty-http")
implementation("jakarta.annotation:jakarta.annotation-api")
@ -367,6 +370,12 @@ def configurationPropertiesMetadataAggregate = aggregates.create("configurationP
usage = "configuration-properties-metadata"
}
def checkAggregatedSpringConfigurationMetadata = tasks.register("checkAggregatedSpringConfigurationMetadata", org.springframework.boot.build.context.properties.CheckAggregatedSpringConfigurationMetadata) {
configurationPropertyMetadata = configurationPropertiesMetadataAggregate.files
reportLocation = layout.buildDirectory.file("checkAggregatedSpringConfigurationMetadata/report.txt")
}
tasks.named("check") { dependsOn checkAggregatedSpringConfigurationMetadata }
tasks.register("documentConfigurationProperties", org.springframework.boot.build.context.properties.DocumentConfigurationProperties) {
configurationPropertyMetadata = configurationPropertiesMetadataAggregate.files
deprecated = false

View File

@ -479,8 +479,6 @@
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#deployment.cloud.aws.beanstalk.tomcat-platform]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#cloud-deployment-aws-beanstalk]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#deployment.cloud.aws.beanstalk]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#cloud-deployment-aws-summary]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.summary[#deployment.cloud.aws.summary]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#cloud-deployment-aws]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#deployment.cloud.aws]
* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.azure[#deployment.cloud.azure]

View File

@ -207,41 +207,20 @@ This file will not be packaged in your uber jar or your container.
[[howto.data-initialization.migration-tool.liquibase-tests]]
=== Use Liquibase for Test-only Migrations
If you want to create Liquibase migrations which populate your test database, you have to create a test changelog which also includes the production changelog.
If you want to create Liquibase migrations which populate your test database, you can leverage https://docs.liquibase.com/reference-guide/changelog-attributes/what-are-contexts[Liquibase contexts].
See also the related https://www.liquibase.com/blog/contexts-vs-labels[blog post].
First, you need to configure Liquibase to use a different changelog when running the tests.
One way to do this is to create a Spring Boot `test` profile and put the Liquibase properties in there.
For that, create a file named `src/test/resources/application-test.properties` and put the following property in there:
In practical terms, this translates into adding a `context:@test` attribute to changesets containing test data, for example:
[configprops,yaml]
[source,sql]
----
spring:
liquibase:
change-log: "classpath:/db/changelog/db.changelog-test.yaml"
--liquibase formatted sql
--changeset alice:1 context:@test
insert into project (id, name) values (1, 'Spring Boot');
----
This configures Liquibase to use a different changelog when running in the `test` profile.
Now create the changelog file at `src/test/resources/db/changelog/db.changelog-test.yaml`:
[source,yaml]
----
databaseChangeLog:
- include:
file: classpath:/db/changelog/db.changelog-master.yaml
- changeSet:
runOrder: "last"
id: "test"
changes:
# Insert your changes here
----
This changelog will be used when the tests are run and it will not be packaged in your uber jar or your container.
It includes the production changelog and then declares a new changeset, whose `runOrder: last` setting specifies that it runs after all the production changesets have been run.
You can now use for example the https://docs.liquibase.com/change-types/insert.html[insert changeset] to insert data or the https://docs.liquibase.com/change-types/sql.html[sql changeset] to execute SQL directly.
The last thing to do is to configure Spring Boot to activate the `test` profile when running tests.
To do this, you can add the `@ActiveProfiles("test")` annotation to your javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] annotated test classes.
And using `spring.liquibase.contexts=test` in environments where you would like changesets containing test data to be applied.

View File

@ -252,17 +252,25 @@ https://www.openshift.com/[OpenShift] has many resources describing how to deplo
[[howto.deployment.cloud.aws]]
== Amazon Web Services (AWS)
Amazon Web Services offers multiple ways to install Spring Boot-based applications, either as traditional web applications (war) or as executable jar files with an embedded web server.
The options include:
Amazon Web Services provides several options that are suitable for running Spring Boot-based applications, either as containers, traditional web applications (war), or self-contained executable jar files.
Popular options are:
* Amazon Elastic Container Service (ECS)
* AWS Elastic Beanstalk
* AWS Code Deploy
* AWS OPS Works
* AWS Cloud Formation
* AWS Container Registry
Each has different features and pricing models.
In this document, we describe to approach using AWS Elastic Beanstalk.
[[howto.deployment.cloud.aws.ecs]]
=== Amazon Elastic Container Service (ECS)
Official https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html[Amazon ECS developer guide] provides comprehensive overview of platform's features and includes https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started.html[getting started guide] that walks you through the steps needed to get your containers up and running.
NOTE: Spring Boot applications can be packaged in Docker containers using techniques described in xref:reference:packaging/container-images/index.adoc[].
In addition to the developer guide, AWS also provides a https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-container-image.html[topical guide] for deploying containerized Java services on Amazon ECS using AWS Fargate.
TIP: Spring Boot auto-detects AWS ECS deployment environments by checking the environment for the `AWS_EXECUTION_ENV` variable.
You can override this detection with the configprop:spring.main.cloud-platform[] configuration property.
@ -278,8 +286,9 @@ You can either use the "`Tomcat Platform`" or the "`Java SE platform`".
==== Using the Tomcat Platform
This option applies to Spring Boot projects that produce a war file.
No special configuration is required.
You need only follow the official guide.
Follow the official guide and https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/tomcat-quickstart.html[Java on Tomcat tutorial].
NOTE: Creating deployable war for a Spring Boot application is described in xref:deployment/traditional-deployment.adoc[].
@ -287,51 +296,8 @@ You need only follow the official guide.
==== Using the Java SE Platform
This option applies to Spring Boot projects that produce a jar file and run an embedded web container.
Elastic Beanstalk environments run an nginx instance on port 80 to proxy the actual application, running on port 5000.
To configure it, add the following line to your `application.properties` file:
[configprops,yaml]
----
server:
port: 5000
----
[TIP]
.Upload binaries instead of sources
====
By default, Elastic Beanstalk uploads sources and compiles them in AWS.
However, it is best to upload the binaries instead.
To do so, add lines similar to the following to your `.elasticbeanstalk/config.yml` file:
[source,xml]
----
deploy:
artifact: target/demo-0.0.1-SNAPSHOT.jar
----
====
[TIP]
.Reduce costs by setting the environment type
====
By default an Elastic Beanstalk environment is load balanced.
The load balancer has a significant cost.
To avoid that cost, set the environment type to "`Single instance`", as described in https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-create-wizard.html#environments-create-wizard-capacity[the Amazon documentation].
You can also create single instance environments by using the CLI and the following command:
[source]
----
eb create -s
----
====
[[howto.deployment.cloud.aws.summary]]
=== Summary
This is one of the easiest ways to get to AWS, but there are more things to cover, such as how to integrate Elastic Beanstalk into any CI / CD tool, use the Elastic Beanstalk Maven plugin instead of the CLI, and others.
There is a https://exampledriven.wordpress.com/2017/01/09/spring-boot-aws-elastic-beanstalk-example/[blog post] covering these topics more in detail.
Follow the official guide and https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-quickstart.html[Java tutorial].
There are also community provided tutorials such as https://www.baeldung.com/spring-boot-deploy-aws-beanstalk[this one].

View File

@ -33,9 +33,9 @@ apply plugin: 'war'
----
The final step in the process is to ensure that the embedded servlet container does not interfere with the servlet container to which the war file is deployed.
To do so, you need to mark the embedded servlet runtime dependency as being provided.
If you use Maven, the following example marks the servlet runtime (Tomcat, in this case) as being provided:
For Maven, you need to mark the embedded servlet container dependency as being `provided`.
For example:
[source,xml]
----
@ -43,20 +43,21 @@ If you use Maven, the following example marks the servlet runtime (Tomcat, in th
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-tomcat-runtime</artifactId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
----
If you use Gradle, the following example marks the servlet runtime (Tomcat, in this case) as being provided:
If you use Gradle, you need to move only the runtime dependencies into the `providedRuntime` configuration.
For example:
[source,gradle]
----
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-tomcat-runtime'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat-runtime'
// ...
}
----

View File

@ -37,6 +37,8 @@ NOTE: The CNB builder used for the images is `paketobuildpacks/builder-noble-jav
It has a small footprint and reduced attack surface. It does not include a shell and contains a reduced set of system libraries.
If you need more tools in the resulting image, you can use `paketobuildpacks/ubuntu-noble-run:latest` as the *run* image.
NOTE: You have to build your application with at least JDK 25, because Buildpacks use the same GraalVM native-image version as the Java version used for compilation.
[[howto.native-image.developing-your-first-application.buildpacks.system-requirements]]

View File

@ -247,7 +247,7 @@ For more detail, see the following sections:
Spring Boot installs a '`whitelabel`' error page that you see in a browser client if you encounter a server error (machine clients consuming JSON and other media types should see a sensible response with the right error code).
NOTE: Set `server.error.whitelabel.enabled=false` to switch the default error page off.
NOTE: Set configprop:spring.web.error.whitelabel.enabled[] to `false` to switch the default error page off.
Doing so restores the default of the servlet container that you are using.
Note that Spring Boot still tries to resolve the error view, so you should probably add your own error page rather than disabling it completely.

View File

@ -18,13 +18,18 @@ Many Spring Boot starters include default embedded containers.
When switching to a different HTTP server, you need to swap the default dependencies for those that you need instead.
To help with this process, Spring Boot provides a separate starter for each of the supported HTTP servers.
The following Maven example shows how to exclude Tomcat and include Jetty for Spring MVC:
The following example shows how to exclude Tomcat and include Jetty for Spring MVC:
[tabs]
======
Maven::
+
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
@ -39,23 +44,70 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
----
+
The following Gradle example configures the necessary dependencies and a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement] to use Tomcat in place of Reactor Netty for Spring WebFlux:
Gradle::
+
[source,gradle]
----
dependencies {
implementation "org.springframework.boot:spring-boot-starter-tomcat"
implementation "org.springframework.boot:spring-boot-starter-webflux"
modules {
module("org.springframework.boot:spring-boot-starter-reactor-netty") {
replacedBy("org.springframework.boot:spring-boot-starter-tomcat", "Use Tomcat instead of Reactor Netty")
}
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
// Exclude the Tomcat dependency
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
// Use Jetty instead
implementation "org.springframework.boot:spring-boot-starter-jetty"
}
----
+
======
NOTE: `spring-boot-starter-reactor-netty` is required to use the javadoc:org.springframework.web.reactive.function.client.WebClient[] class, so you may need to keep a dependency on Netty even when you need to include a different HTTP server.
If you are creating a war file, you can use a similar approach, but you must indicate provided dependencies:
[tabs]
======
Maven::
+
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>provided</scope>
</dependency>
----
+
Gradle::
+
[source,gradle]
----
dependencies {
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
// Exclude the Tomcat dependency
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
// Use Jetty instead
implementation "org.springframework.boot:spring-boot-starter-jetty"
providedRuntime "org.springframework.boot:spring-boot-starter-jetty-runtime"
}
----
+
======

View File

@ -383,6 +383,17 @@ management:
TIP: See javadoc:org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties[] for a complete list of options.
[[actuator.endpoints.json]]
== JSON
When working with JSON, Jackson is used for serialization and deserialization.
By default, an isolated javadoc:tools.jackson.databind.json.JsonMapper[] is used.
This isolation means that it does not share the same configuration as the application's `JsonMapper` and it is not affected by `spring.jackson.*` properties.
To disable this behavior and configure Actuator to use the application's `JsonMapper`, set configprop:management.endpoints.jackson.isolated-json-mapper[] to `false`.
Alternatively, you can define your own javadoc:org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper[] bean that produces a `JsonMapper` that meets your needs.
Actuator will then use it for JSON processing.
[[actuator.endpoints.implementing-custom]]
== Implementing Custom Endpoints
@ -674,8 +685,8 @@ with the `key` listed in the following table:
TIP: You can disable them all by setting the configprop:management.health.defaults.enabled[] property.
TIP: The `ssl` javadoc:org.springframework.boot.actuate.health.HealthIndicator[] has a "warning threshold" property named configprop:management.health.ssl.certificate-validity-warning-threshold[].
If an SSL certificate will be invalid within the time span defined by this threshold, the javadoc:org.springframework.boot.actuate.health.HealthIndicator[] will warn you but it will still return HTTP 200 to not disrupt the application.
You can use this threshold to give yourself enough lead time to rotate the soon to be expired certificate.
You can use this threshold to give yourself enough lead time to rotate the soon-to-be-expired certificate.
If an SSL certificate will become invalid within the period defined by this threshold, the javadoc:org.springframework.boot.actuate.health.HealthIndicator[] will report this in the details section of its response where `details.validChains.certificates.[*].validity.status` will have the value `WILL_EXPIRE_SOON`.
Additional javadoc:org.springframework.boot.actuate.health.HealthIndicator[] beans are enabled by default:
@ -1260,7 +1271,7 @@ The `info` endpoint publishes information about your process, see javadoc:org.sp
[[actuator.endpoints.info.ssl-information]]
=== SSL Information
The `info` endpoint publishes information about your SSL certificates (that are configured through xref:features/ssl.adoc#features.ssl.bundles[SSL Bundles]), see javadoc:org.springframework.boot.info.SslInfo[] for more details. This endpoint reuses the "warning threshold" property of javadoc:org.springframework.boot.health.info.SslHealthIndicator[]: if an SSL certificate will be invalid within the time span defined by this threshold, it will trigger a warning. See the `management.health.ssl.certificate-validity-warning-threshold` property.
The `info` endpoint publishes information about your SSL certificates (that are configured through xref:features/ssl.adoc#features.ssl.bundles[SSL Bundles]), see javadoc:org.springframework.boot.info.SslInfo[] for more details.

View File

@ -29,6 +29,11 @@ Observability support relies on the https://github.com/micrometer-metrics/contex
By default, javadoc:java.lang.ThreadLocal[] values are not automatically reinstated in reactive operators.
This behavior is controlled with the configprop:spring.reactor.context-propagation[] property, which can be set to `auto` to enable automatic propagation.
If you're working with javadoc:org.springframework.scheduling.annotation.Async[format=annotation] methods or use an javadoc:org.springframework.core.task.AsyncTaskExecutor[], you have to register the javadoc:org.springframework.core.task.support.ContextPropagatingTaskDecorator[] on the executor, otherwise the observability context is lost when switching threads.
This can be done using this configuration:
include-code::ContextPropagationConfiguration[]
For more details about observations please see the {url-micrometer-docs}/observation[Micrometer Observation documentation].
@ -82,6 +87,18 @@ The preceding example will prevent all observations whose name contains "denied"
[[actuator.observability.annotations]]
== Micrometer Observation Annotations support
To enable scanning of observability annotations like javadoc:io.micrometer.observation.annotation.Observed[format=annotation], javadoc:io.micrometer.core.annotation.Timed[format=annotation], javadoc:io.micrometer.core.annotation.Counted[format=annotation], javadoc:io.micrometer.core.aop.MeterTag[format=annotation] and javadoc:io.micrometer.tracing.annotation.NewSpan[format=annotation], you need to set the configprop:management.observations.annotations.enabled[] property to `true`.
This feature is supported by Micrometer directly.
Please refer to the {url-micrometer-docs-concepts}/timers.html#_the_timed_annotation[Micrometer], {url-micrometer-docs-observation}/components.html#micrometer-observation-annotations[Micrometer Observation] and {url-micrometer-tracing-docs}/api.html#_aspect_oriented_programming[Micrometer Tracing] reference docs.
NOTE: When you annotate methods or classes which are already instrumented (for example, xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[Spring Data repositories] or xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[Spring MVC controllers]), you will get duplicate observations.
In that case you can either disable the automatic instrumentation using xref:reference:actuator/observability.adoc#actuator.observability.preventing-observations[properties] or an javadoc:io.micrometer.observation.ObservationPredicate[] and rely on your annotations, or you can remove your annotations.
[[actuator.observability.opentelemetry]]
== OpenTelemetry Support
@ -101,24 +118,82 @@ Auto-configured attributes will be merged with attributes from the `OTEL_RESOURC
If you have defined your own javadoc:io.opentelemetry.sdk.resources.Resource[] bean, this will no longer be the case.
NOTE: Spring Boot does not provide auto-configuration for OpenTelemetry metrics or logging.
OpenTelemetry tracing is only auto-configured when used together with xref:actuator/tracing.adoc[Micrometer Tracing].
NOTE: Spring Boot does not provide automatic exporting of OpenTelemetry metrics or logs.
Exporting OpenTelemetry traces is only auto-configured when used together with xref:actuator/tracing.adoc[Micrometer Tracing].
[[actuator.observability.opentelemetry.environment-variables]]
=== Environment variables
Spring Boot supports the following environment variables to configure the OpenTelemetry resource:
* https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration[`OTEL_RESOURCE_ATTRIBUTES`]
* https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration[`OTEL_SERVICE_NAME`]
NOTE: The `OTEL_RESOURCE_ATTRIBUTES` environment variable consists of a list of key-value pairs.
For example: `key1=value1,key2=value2,key3=spring%20boot`.
All attribute values are treated as strings, and any characters outside the baggage-octet range must be **percent-encoded**.
Micrometer also supports the following environment variables to configure the metrics export over OTLP:
The next sections will provide more details about logging, metrics and traces.
* https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_endpoint[`OTEL_EXPORTER_OTLP_ENDPOINT`]
* https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_metrics_endpoint[`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`]
* https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_headers[`OTEL_EXPORTER_OTLP_HEADERS`]
* https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/#otel_exporter_otlp_metrics_headers[`OTEL_EXPORTER_OTLP_METRICS_HEADERS`]
Other environment variables as described in https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/[the OpenTelemetry documentation] are not supported.
If you want all environment variables specified by OpenTelemetry's SDK to be effective, you have to supply your own `OpenTelemetry` bean.
WARNING: Doing this will switch off Spring Boot's OpenTelemetry auto-configuration and may break the built-in observability functionality.
First, add a dependency to `io.opentelemetry:opentelemetry-sdk-extension-autoconfigure` to get https://opentelemetry.io/docs/languages/java/configuration/#zero-code-sdk-autoconfigure[OpenTelemetry's zero-code SDK autoconfigure module], then add this configuration:
include-code::AutoConfiguredOpenTelemetrySdkConfiguration[]
[[actuator.observability.annotations]]
== Micrometer Observation Annotations support
[[actuator.observability.opentelemetry.logging]]
=== Logging
To enable scanning of observability annotations like javadoc:io.micrometer.observation.annotation.Observed[format=annotation], javadoc:io.micrometer.core.annotation.Timed[format=annotation], javadoc:io.micrometer.core.annotation.Counted[format=annotation], javadoc:io.micrometer.core.aop.MeterTag[format=annotation] and javadoc:io.micrometer.tracing.annotation.NewSpan[format=annotation], you need to set the configprop:management.observations.annotations.enabled[] property to `true`.
This feature is supported by Micrometer directly.
Please refer to the {url-micrometer-docs-concepts}/timers.html#_the_timed_annotation[Micrometer], {url-micrometer-docs-observation}/components.html#micrometer-observation-annotations[Micrometer Observation] and {url-micrometer-tracing-docs}/api.html#_aspect_oriented_programming[Micrometer Tracing] reference docs.
The javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration[] configures OpenTelemetry's javadoc:io.opentelemetry.sdk.logs.SdkLoggerProvider[].
Exporting logs via OTLP is supported through the javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration[], which enables OTLP log exporting over HTTP or gRPC.
NOTE: When you annotate methods or classes which are already instrumented (for example, xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[Spring Data repositories] or xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[Spring MVC controllers]), you will get duplicate observations.
In that case you can either disable the automatic instrumentation using xref:reference:actuator/observability.adoc#actuator.observability.preventing-observations[properties] or an javadoc:io.micrometer.observation.ObservationPredicate[] and rely on your annotations, or you can remove your annotations.
However, while there is a `SdkLoggerProvider` bean, Spring Boot doesn't support bridging logs to this bean out of the box.
This can be done with 3rd-party log bridges, as described in the xref:reference:actuator/loggers.adoc#actuator.loggers.opentelemetry[Logging with OpenTelemetry] section.
[[actuator.observability.opentelemetry.metrics]]
=== Metrics
The choice of metrics in the Spring portfolio is Micrometer, which means that metrics are not collected and exported through the OpenTelemetry's javadoc:io.opentelemetry.sdk.metrics.SdkMeterProvider[].
Spring Boot doesn't provide a `SdkMeterProvider` bean.
However, Micrometer metrics can be exported via OTLP to any OpenTelemetry capable backend using the javadoc:io.micrometer.registry.otlp.OtlpMeterRegistry[], as described in the xref:reference:actuator/metrics.adoc#actuator.metrics.export.otlp[Metrics with OTLP] section.
NOTE: Micrometer's OTLP registry doesn't use the `Resource` bean, but setting `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` or configprop:management.opentelemetry.resource-attributes[] works.
[[actuator.observability.opentelemetry.metrics.api-and-sdk]]
==== Metrics via the OpenTelemetry API and SDK
If you or a dependency you include make use of OpenTelemetry's javadoc:io.opentelemetry.api.metrics.MeterProvider[], those metrics are not exported.
We strongly recommend that you report your metrics with Micrometer.
If a dependency you include uses OpenTelemetry's `MeterProvider`, you can include this configuration in your application to configure a `MeterProvider` bean, which you then have to wire into your dependency:
include-code::OpenTelemetryMetricsConfiguration[]
This configuration also enables metrics export via OTLP over HTTP.
[[actuator.observability.opentelemetry.tracing]]
=== Tracing
If Micrometer tracing is used, the javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingAutoConfiguration[] configures OpenTelemetry's javadoc:io.opentelemetry.sdk.trace.SdkTracerProvider[].
Exporting traces through OTLP is enabled by the javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration[], which supports exporting traces with OTLP over HTTP or gRPC.
We strongly recommend using the Micrometer Observation or Tracing API instead of using the OpenTelemetry API directly.

View File

@ -341,7 +341,7 @@ To take full control over the client's configuration, define a javadoc:co.elasti
Additionally, a javadoc:co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer[] is auto-configured to automatically discover nodes from a running Elasticsearch cluster and set them on the javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[] bean.
Additionally, a javadoc:co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer[] can be auto-configured to automatically discover nodes from a running Elasticsearch cluster and set them on the javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[] bean.
You can further tune how javadoc:co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer[] is configured, as shown in the following example:
[configprops,yaml]
@ -350,18 +350,17 @@ spring:
elasticsearch:
restclient:
sniffer:
enabled: true
interval: "10m"
delay-after-failure: "30s"
----
To disable auto-configuration of the Sniffer, set configprop:spring.elasticsearch.restclient.sniffer.enabled[] to `false`.
[[data.nosql.elasticsearch.connecting-using-rest.javaapiclient]]
==== Connecting to Elasticsearch Using ElasticsearchClient
If you have `co.elastic.clients:elasticsearch-java` on the classpath, Spring Boot will auto-configure and register an javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] bean.
If you use the `spring-boot-starter-elasticsearch` or have added `co.elastic.clients:elasticsearch-java` to the classpath, Spring Boot will auto-configure and register an javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] bean.
The javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] uses a transport that depends upon the previously described javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[].
Therefore, the properties described previously can be used to configure the javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[].

View File

@ -795,12 +795,8 @@ NOTE: The properties that map to javadoc:org.springframework.boot.context.proper
Such arrangement relies on a default empty constructor and getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC.
A setter may be omitted in the following cases:
* Maps, as long as they are initialized, need a getter but not necessarily a setter, since they can be mutated by the binder.
* Collections and arrays can be accessed either through an index (typically with YAML) or by using a single comma-separated value (properties).
In the latter case, a setter is mandatory.
We recommend to always add a setter for such types.
If you initialize a collection, make sure it is not immutable (as in the preceding example).
* If nested POJO properties are initialized (like the `Security` field in the preceding example), a setter is not required.
* Pre-initialized Maps and Collections, as long as they are initialized with a mutable implementation (like the `roles` field in the preceding example).
* Pre-initialized nested POJOs (like the `Security` field in the preceding example).
If you want the binder to create the instance on the fly by using its default constructor, you need a setter.
Some people use Project Lombok to add getters and setters automatically.

View File

@ -101,4 +101,4 @@ The preferred JSON-B implementation is Eclipse Yasson for which dependency manag
Auto-configuration for Kotlin Serialization is provided.
When `kotlinx-serialization-json` is on the classpath a https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/[Json] bean is automatically configured.
Several `+spring.kotlin.serialization.*+` configuration properties are provided for customizing the configuration.
Several `+spring.kotlinx.serialization.json.*+` configuration properties are provided for customizing the configuration.

View File

@ -142,10 +142,7 @@ spring:
Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property.
If a custom javadoc:org.infinispan.configuration.cache.ConfigurationBuilder[] bean is defined, it is used to customize the caches.
To be compatible with Spring Boot's Jakarta EE 9 baseline, Infinispan's `-jakarta` modules must be used.
For every module with a `-jakarta` variant, the variant must be used in place of the standard module.
For example, `infinispan-core-jakarta` and `infinispan-commons-jakarta` must be used in place of `infinispan-core` and `infinispan-commons` respectively.
For more details, see https://infinispan.org/docs/stable/titles/spring/spring.html[the documentation].
[[io.caching.provider.couchbase]]

View File

@ -56,6 +56,7 @@ NOTE: Your executable jar must include AOT generated assets such as generated cl
Spring Boot applications usually use Cloud Native Buildpacks through the Maven (`mvn spring-boot:build-image`) or Gradle (`gradle bootBuildImage`) integrations.
You can, however, also use {url-buildpacks-docs}/for-platform-operators/how-to/integrate-ci/pack/[`pack`] to turn an AOT processed Spring Boot executable jar into a native container image.
NOTE: You have to build your application with at least JDK 25, because Buildpacks use the same GraalVM native-image version as the Java version used for compilation.
First, make sure that a Docker daemon is available (see https://docs.docker.com/installation/#installation[Get Docker] for more details).
https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux.

View File

@ -325,7 +325,7 @@ Usually, you would define the properties in your `application.properties` or `ap
Common server settings include:
* Network settings: Listen port for incoming HTTP requests (`server.port`), interface address to bind to (`server.address`), and so on.
* Error management: Location of the error page (`server.error.path`) and so on.
* Error management: Location of the error page (configprop:spring.web.error.path[]) and so on.
* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[SSL]
* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[HTTP compression]

View File

@ -589,6 +589,14 @@ The single `onStartup` method provides access to the javadoc:jakarta.servlet.Ser
[[web.servlet.embedded-container.context-initializer.init-parameters]]
==== Init Parameters
Init parameters can be configured on the javadoc:jakarta.servlet.ServletContext[] using `server.servlet.context-parameters.*` properties.
For example, the property `server.servlet.context-parameters.com.example.parameter=example` will configure a `ServletContext` init parameter named `com.example.parameter` with the value `example`.
[[web.servlet.embedded-container.context-initializer.scanning]]
==== Scanning for Servlets, Filters, and listeners
@ -628,7 +636,7 @@ Common server settings include:
* Network settings: Listen port for incoming HTTP requests (`server.port`), interface address to bind to (`server.address`), and so on.
* Session settings: Whether the session is persistent (`server.servlet.session.persistent`), session timeout (`server.servlet.session.timeout`), location of session data (`server.servlet.session.store-dir`), and session-cookie configuration (`server.servlet.session.cookie.*`).
* Error management: Location of the error page (`server.error.path`) and so on.
* Error management: Location of the error page (configprop:spring.web.error.path[]) and so on.
* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[SSL]
* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[HTTP compression]

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.docs.actuator.observability.contextpropagation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;
@Configuration(proxyBeanMethods = false)
class ContextPropagationConfiguration {
@Bean
ContextPropagatingTaskDecorator contextPropagatingTaskDecorator() {
return new ContextPropagatingTaskDecorator();
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.docs.actuator.observability.opentelemetry.environmentvariables;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
class AutoConfiguredOpenTelemetrySdkConfiguration {
@Bean
OpenTelemetry autoConfiguredOpenTelemetrySdk() {
return AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* https://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 org.springframework.boot.docs.actuator.observability.opentelemetry.metrics.apiandsdk;
import java.time.Duration;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
class OpenTelemetryMetricsConfiguration {
@Bean
OtlpHttpMetricExporter metricExporter() {
String endpoint = "http://localhost:4318/v1/metrics";
return OtlpHttpMetricExporter.builder().setEndpoint(endpoint).build();
}
@Bean
PeriodicMetricReader metricReader(MetricExporter exporter) {
Duration interval = Duration.ofMinutes(1);
return PeriodicMetricReader.builder(exporter).setInterval(interval).build();
}
@Bean
SdkMeterProvider meterProvider(Resource resource, MetricReader metricReader) {
return SdkMeterProvider.builder().registerMetricReader(metricReader).setResource(resource).build();
}
}

View File

@ -33,7 +33,7 @@ public class MyProperties {
}
@Deprecated
@DeprecatedConfigurationProperty(replacement = "my.app.name")
@DeprecatedConfigurationProperty(replacement = "my.app.name", since = "1.2.0")
public String getTarget() {
return this.name;
}

View File

@ -30,11 +30,11 @@ public final class MyAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SomeService.class)
public static class SomeServiceConfiguration {
static class SomeServiceConfiguration {
@Bean
@ConditionalOnMissingBean
public SomeService someService() {
SomeService someService() {
return new SomeService();
}

View File

@ -25,8 +25,8 @@ public class MyHttpMessageConvertersConfiguration {
@Bean
public ClientHttpMessageConvertersCustomizer myClientConvertersCustomizer() {
return (clientBuilder) -> clientBuilder.customMessageConverter(new AdditionalHttpMessageConverter())
.customMessageConverter(new AnotherHttpMessageConverter());
return (clientBuilder) -> clientBuilder.addCustomConverter(new AdditionalHttpMessageConverter())
.addCustomConverter(new AnotherHttpMessageConverter());
}
}

Some files were not shown because too many files have changed in this diff Show More