Compare commits

...

256 Commits

Author SHA1 Message Date
Stéphane Nicoll 33038d3e1e Exclude shaded JSON packages from 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-47207
2025-10-08 13:59:08 +02:00
Stéphane Nicoll b66509b4e1 Merge pull request #46410 from ppkarwasz
* pr/46410:
  Polish "Add runtime hints for Log4j Core 2"
  Add runtime hints for Log4j Core 2

Closes gh-46410
2025-10-08 10:44:58 +02:00
Stéphane Nicoll e20e2393c9 Polish "Add runtime hints for Log4j Core 2"
See gh-46410
2025-10-08 10:41:40 +02:00
Piotr P. Karwasz a2d4ecf8ac Add runtime hints for Log4j Core 2
This change introduces runtime hints for Log4j Core 2 to support its
integration with Spring Boot native images.

Starting with Log4j 2.25.x, Log4j includes built-in GraalVM reachability
metadata, allowing native image generation without requiring additional
manual configuration.

This contribution complements that by adding Spring Boot–specific
metadata:

* Registers default Spring Boot configuration files.
* Registers classes referenced via `ClassUtils.isPresent(...)` checks.

See gh-46410

Signed-off-by: Piotr P. Karwasz <piotr@github.copernik.eu>
2025-10-08 10:39:24 +02:00
Phillip Webb 05172cf77b Use ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES to check timestamp
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
Update `AbstractBootArchiveTests` to use the Gradle provided constant
to check the repeatable timestamp.
2025-10-07 22:29:18 -07:00
Stéphane Nicoll 4420c92173 Adapt Kotlin null-safety with Spring Framework changes
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-47428
2025-10-07 15:44:09 +02:00
Stéphane Nicoll da8eac3483 Update RetryPolicySettings to configure exception policy as well
Closes gh-47264
2025-10-07 14:07:17 +02:00
Stéphane Nicoll cb51a44e2b Merge branch '3.5.x'
Closes gh-47426
2025-10-07 11:44:47 +02:00
Stéphane Nicoll 5e04d98260 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-47425
2025-10-07 11:44:06 +02:00
Stéphane Nicoll 61acc52137 Merge pull request #47415 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
* pr/47415:
  Polish "Bump jfrog/setup-jfrog-cli from 4.6.1 to 4.7.0"
  Bump jfrog/setup-jfrog-cli from 4.6.1 to 4.7.0

Closes gh-47415
2025-10-07 11:43:58 +02:00
Stéphane Nicoll f1a3971148 Polish "Bump jfrog/setup-jfrog-cli from 4.6.1 to 4.7.0"
See gh-47415
2025-10-07 11:43:41 +02:00
dependabot[bot] dd353034de Bump jfrog/setup-jfrog-cli from 4.6.1 to 4.7.0
Bumps [jfrog/setup-jfrog-cli](https://github.com/jfrog/setup-jfrog-cli) from 4.6.1 to 4.7.0.
- [Release notes](https://github.com/jfrog/setup-jfrog-cli/releases)
- [Commits](88e9eba31c...c32bf10843)

---
updated-dependencies:
- dependency-name: jfrog/setup-jfrog-cli
  dependency-version: 4.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

See gh-47415

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-07 11:42:43 +02:00
Stéphane Nicoll c2e838a603 Merge pull request #47381 from meistermeier
* pr/47381:
  Polish "Add support for Neo4j Java Driver 6.0.0"
  Add support for Neo4j Java Driver 6.0.0

Closes gh-47381
2025-10-07 11:37:32 +02:00
Stéphane Nicoll 6f1bcc4bfa Polish "Add support for Neo4j Java Driver 6.0.0"
See gh-47381
2025-10-07 11:37:25 +02:00
Gerrit Meier 2542430e5b Add support for Neo4j Java Driver 6.0.0
See gh-47381

Signed-off-by: Gerrit Meier <meistermeier@gmail.com>
2025-10-07 11:37:25 +02:00
Stéphane Nicoll 43b06ca9b9 Start building against Spring Data Bom 2025.1.0-RC1 snapshots
See gh-47394
2025-10-07 11:37:12 +02:00
Stéphane Nicoll 533544d8fc Polish 2025-10-07 10:39:54 +02:00
Andy Wilkinson 5ec993bb8c Upgrade to Dokka 2.1.0-Beta
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
We need to upgrade for better compatibility with Java 25.

See gh-47413
2025-10-07 07:02:57 +01:00
Andy Wilkinson 1ebc557bd5 Consistent configuration of test repository URLs
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-10-06 23:09:27 +01:00
Andy Wilkinson 2eaad0585c Consistent configuration of docker-test-maven-repository 2025-10-06 22:21:36 +01:00
Andy Wilkinson 46022d2a4e Third time lucky fixing the Windows build?
See 44099d3d, c1924f2, a5dbc5b
2025-10-06 20:19:03 +01:00
Andy Wilkinson a5dbc5bb22 Alternative attempt at fixing the Windows build
See 44099d3d, c1924f2
2025-10-06 19:48:06 +01:00
Andy Wilkinson 16718f676d Upgrade to Detekt 2.0.0-alpha.0
We need to upgrade for better compatibility with Java 25.

See gh-47413
2025-10-06 19:41:08 +01:00
Andy Wilkinson c1924f2fcd Try to fix Windows build
See 44099d3d
2025-10-06 19:32:53 +01:00
Andy Wilkinson 473fc1b19e Merge branch '3.5.x'
Closes gh-47413
2025-10-06 18:44:02 +01:00
Andy Wilkinson a79d0e0d10 Remove Java 24 from CI matrix
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-47412
2025-10-06 18:42:42 +01:00
Andy Wilkinson 44099d3d21 Build with Gradle 9.1.0 2025-10-06 18:30:48 +01:00
Stéphane Nicoll 2440667aab Polish
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: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:false version:24], 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
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: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-10-06 16:37:10 +02:00
Stéphane Nicoll 7db43ef820 Mark spring-web optional in spring-boot-rsocket
This commit moves the spring-web dependency from implementation to
optional. It also adds an api dependency to spring-web in the rsocket
starter.

The reasoning behind this change is that RSocket can be used without
spring-web, and we want to make sure that consumers of the dependency
can achieve that goal, as they were able to in previous versions.

However, we believe that most RSocket-based applications need spring-web
as, without it, only the simple and not efficient implementation of
RouterMatcher is available. With the addition of exception handling
using ControllerAdvice, this change makes also sure that it works out
of the box with the starter.

Closes gh-47409
2025-10-06 16:31:09 +02:00
Moritz Halbritter d97539bc46 Add nullability annotations to tests in module/spring-boot-data-couchbase-test
See gh-47263
2025-10-06 13:10:55 +02:00
Moritz Halbritter 8c25063273 Add nullability annotations to tests in module/spring-boot-liquibase
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter 489336255a Add nullability annotations to tests in module/spring-boot-ldap
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter fde0ae4ac9 Add nullability annotations to tests in module/spring-boot-kotlin-serialization
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter 643f6112c7 Add nullability annotations to tests in module/spring-boot-kafka
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter 4bf6fcefab Add nullability annotations to tests in module/spring-boot-jsonb
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter 9d85c379bd Add nullability annotations to tests in module/spring-boot-jpa-test
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter 9d63a74bbc Add nullability annotations to tests in module/spring-boot-jpa
See gh-47263
2025-10-06 13:07:58 +02:00
Moritz Halbritter f059a953d3 Add nullability annotations to tests in module/spring-boot-jooq-test
See gh-47263
2025-10-06 13:07:57 +02:00
Moritz Halbritter 1f293cc653 Add nullability annotations to tests in module/spring-boot-jooq
See gh-47263
2025-10-06 13:07:57 +02:00
Moritz Halbritter 49c7546662 Add nullability annotations to tests in module/spring-boot-jms
See gh-47263
2025-10-06 13:07:57 +02:00
Moritz Halbritter c92617a015 Add nullability annotations to tests in module/spring-boot-jetty
See gh-47263
2025-10-06 13:07:57 +02:00
Andy Wilkinson a9bf744b68 Fix Docker test configuration in spring-boot-data-couchbase-test
See gh-47322
2025-10-06 11:38:45 +01:00
Moritz Halbritter b503ad3a9a Add nullability annotations to tests in module/spring-boot-jdbc-test
See gh-47263
2025-10-06 12:03:58 +02:00
Moritz Halbritter a350ead232 Add nullability annotations to tests in module/spring-boot-data-redis-test
See gh-47263
2025-10-06 12:03:58 +02:00
Moritz Halbritter 55a97aa7ad Add nullability annotations to tests in module/spring-boot-data-r2dbc-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 06dd6aec3c Add nullability annotations to tests in module/spring-boot-data-neo4j-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter a1038a5e64 Add nullability annotations to tests in module/spring-boot-data-mongodb-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 99f8c4cd0d Add nullability annotations to tests in module/spring-boot-data-ldap-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 2edd8f9d62 Add nullability annotations to tests in module/spring-boot-data-jpa-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 3353090bc6 Add nullability annotations to tests in module/spring-boot-data-jdbc-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter ad22bc033f Add nullability annotations to tests in module/spring-boot-data-jdbc
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter dee42bfe2d Add nullability annotations to tests in module/spring-boot-data-elasticsearch-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 307dc1c477 Add nullability annotations to tests in module/spring-boot-data-couchbase-test
See gh-47263
2025-10-06 12:03:57 +02:00
Moritz Halbritter 64aad6d060 Add nullability annotations to tests in module/spring-boot-data-cassandra-test
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter 0f41e906b9 Add nullability annotations to tests in module/spring-boot-cache-test
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter c65a259637 Add nullability annotations to tests in module/spring-boot-batch-jdbc
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter 1b44bafda1 Add nullability annotations to tests in core/spring-boot-test-autoconfigure
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter e4a58a53d0 Add nullability annotations to tests in module/spring-boot-jdbc
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter 34a8e1bd82 Improve null-safety of module/spring-boot-jdbc
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter af941e0a9a Add nullability annotations to tests in module/spring-boot-jackson
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter 7f225a8df5 Add nullability annotations to tests in module/spring-boot-integration
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter cae3fb578c Add nullability annotations to tests in module/spring-boot-http-converter
See gh-47263
2025-10-06 12:03:56 +02:00
Moritz Halbritter f175d132b3 Add nullability annotations to tests in module/spring-boot-http-codec
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 2ca6703f55 Add nullability annotations to tests in module/spring-boot-http-client
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter f59fc4020a Add nullability annotations to tests in module/spring-boot-hibernate
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 80c384e92c Add nullability annotations to tests in module/spring-boot-health
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 0634c11eee Add nullability annotations to tests in module/spring-boot-hazelcast
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter bf075ec89c Add nullability annotations to tests in module/spring-boot-hateoas
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter f74ed943e5 Add nullability annotations to tests in module/spring-boot-h2console
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 80436abbb6 Add nullability annotations to tests in module/spring-boot-gson
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 09311ff44e Add nullability annotations to tests in module/spring-boot-groovy-templates
See gh-47263
2025-10-06 12:03:55 +02:00
Moritz Halbritter 9f1e033caf Add nullability annotations to tests in module/spring-boot-graphql-test
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 4854fec275 Add nullability annotations to tests in module/spring-boot-graphql
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter e83ad75d3e Add nullability annotations to tests in module/spring-boot-freemarker
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 657c537cc2 Add nullability annotations to tests in module/spring-boot-flyway
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 0753e7dbf2 Manage version for Checker annotations internally
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 1d4b9d372f Add nullability annotations to tests in module/spring-boot-elasticsearch
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter e878db0abf Add nullability annotations to tests in module/spring-boot-devtools
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 58e2f9c872 Improve null-safety of module/spring-boot-devtools
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 1023ed65a6 Add nullability annotations to tests in module/spring-boot-data-rest
See gh-47263
2025-10-06 12:03:54 +02:00
Moritz Halbritter 266f9c44e0 Add nullability annotations to tests in module/spring-boot-data-redis
See gh-47263
2025-10-06 12:03:53 +02:00
Moritz Halbritter 3fdc1db7ce Add nullability annotations to tests in module/spring-boot-data-r2dbc
See gh-47263
2025-10-06 12:03:53 +02:00
Andy Wilkinson a111f1f68f Upgrade to Liquibase 5.0.1
Closes gh-47386
2025-10-06 11:00:59 +01:00
Stéphane Nicoll b10262c9bc Merge pull request #45360 from dmitrysulman
* pr/47287:
  Polish "Register controller advices to RSocket messaging"
  Register controller advices to RSocket messaging

Closes gh-45360
2025-10-06 11:32:54 +02:00
Stéphane Nicoll 485180df4f Polish "Register controller advices to RSocket messaging"
See gh-45360
2025-10-06 11:29:16 +02:00
Dmitry Sulman 94fce6f689 Register controller advices to RSocket messaging
See gh-45360

Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2025-10-06 11:24:35 +02:00
Stéphane Nicoll 761302452b Merge pull request #46208 from shahabkondri
* pr/46208:
  Polish "Include /fonts/** to common static locations"
  Include /fonts/** to common static locations

Closes gh-46208
2025-10-06 08:52:42 +02:00
Stéphane Nicoll 3f2e1b2466 Polish "Include /fonts/** to common static locations"
See gh-46208
2025-10-06 08:51:17 +02:00
Shahab Kondri 74daedff76 Include /fonts/** to common static locations
This commit updates StaticResourceLocation to include a new entry for
the common locations of fonts. As a result,
StaticResourceRequest#atCommonLocations now includes /fonts/** as well.

See gh-46208

Signed-off-by: Shahab Kondri <shahab.kondri@gmail.com>
2025-10-06 08:40:57 +02:00
Stéphane Nicoll 169b1b10b0 Allow CodecCustomizer to be used out-of-the-box with WebFlux
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: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:false version:24], 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
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: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-47397
2025-10-05 08:55:19 +02:00
Stéphane Nicoll 652414155c Merge pull request #47401 from NeatGuyCoding
* pr/47401:
  Polish "Validate node configuration with static master replica"
  Validate node configuration with static master replica

Closes gh-47401
2025-10-05 08:27:02 +02:00
Stéphane Nicoll 1e4cc948f2 Polish "Validate node configuration with static master replica"
See gh-47401
2025-10-05 08:26:17 +02:00
NeatGuyCoding 4fd9626854 Validate node configuration with static master replica
See gh-47401

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-10-05 08:20:38 +02:00
NeatGuyCoding 8a9528ebdc Fix Javadoc link
See gh-47401

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-10-05 08:19:33 +02:00
Stéphane Nicoll 1ed8eb08e0 Add missing Kotlin example for MockMvc and RestTestClient
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: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:false version:24], 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
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: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-47371
2025-10-03 16:32:11 +02:00
Andy Wilkinson 49ba8aa668 Merge pull request #46520 from academey
* gh-46520:
  Polish "Remove unused SHA-1 hash from UNPACK markers"
  Remove unused SHA-1 hash from UNPACK markers

Closes gh-46520
2025-10-03 15:16:45 +01:00
Andy Wilkinson 53cda6a6a1 Polish "Remove unused SHA-1 hash from UNPACK markers"
See gh-46520
2025-10-03 15:16:36 +01:00
academey d5717b71ab Remove unused SHA-1 hash from UNPACK markers
In BootZipCopyAction and AbstractJarWriter, SHA-1 hash is calculated for
stored entries requiring unpack and set as entry comment. However, the
hash isn't used anywhere, just the marker prefix 'UNPACK:' is checked.

This commit removes the unnecessary SHA-1 hash calculation which reads
the file completely in memory, potentially three times in extreme cases.
Now the comment is simply set to 'UNPACK:' without any hash, improving
performance.

See gh-46520

Signed-off-by: Hyunjoon Choi <hyunjoon@example.com>
Signed-off-by: academey <academey@gmail.com>
2025-10-03 15:16:36 +01:00
Stéphane Nicoll 79ad5e6999 Merge pull request #46975 from dungdm93
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: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:false version:24], 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
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: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/46975:
  Polish "Auto-configure observation of Redis with Lettuce"
  Auto-configure observation of Redis with Lettuce

Closes gh-46975
2025-10-03 14:45:30 +02:00
Stéphane Nicoll 871f82d116 Polish "Auto-configure observation of Redis with Lettuce"
See gh-46975
2025-10-03 14:45:12 +02:00
Đặng Minh Dũng 0187b77761 Auto-configure observation of Redis with Lettuce
See gh-46975

Signed-off-by: Đặng Minh Dũng <dungdm93@live.com>
2025-10-03 14:26:19 +02:00
Stéphane Nicoll 04038101d2 Merge branch '3.5.x'
Closes gh-47393
2025-10-03 14:25:45 +02:00
Stéphane Nicoll 45bf83d737 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: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
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
Closes gh-47392
2025-10-03 14:25:29 +02:00
Stéphane Nicoll f7e7664a5a Adapt links to Lettuce and Jedis
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-47391
2025-10-03 14:25:10 +02:00
Andy Wilkinson 6ee519ec57 Disable test when Docker is not running 2025-10-03 12:29:30 +01:00
Andy Wilkinson 92fe4c55f7 Resolve MariaDB and MySQL dialects through DB query
Spring Data JDBC has deprecated its INSTANCE constants in its MariaDB
and MySQL dialects as the required configuration for the dialect
varies depending on the configuration of the DB.

This commit adapts to this deprecation by changing Boot's
DataJdbcDatabaseDialect to resolve the underlying dialect through a
DB query for its MARIA and MYSQL values.

Closes gh-46062
2025-10-03 09:37:56 +01:00
Stéphane Nicoll 911578e560 Merge pull request #46957 from facewise
* pr/46957:
  Polish "Add support for static master-replica with Lettuce"
  Add support for static master-replica with Lettuce

Closes gh-46957
2025-10-03 10:14:29 +02:00
Stéphane Nicoll fbcc1fdec6 Polish "Add support for static master-replica with Lettuce"
See gh-46957
2025-10-03 10:03:54 +02:00
facewise c280fdefe8 Add support for static master-replica with Lettuce
See gh-46957

Signed-off-by: 용현 <dydguskim@gripcorp.co>
2025-10-03 09:05:14 +02:00
Brian Clozel 319e462cba Use new Jetty CompressionHandler
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: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:false version:24], 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
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: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
Prior to this commit, our Jetty support for compression was using the
`GzipHandler` which is deprecated as of Jetty 12.1.
This commit adds two new dependencies to the module and uses the new
`CompressionHandler` with the `GzipCompression` algorithm.

Closes gh-47134
2025-10-02 22:02:49 +02:00
Moritz Halbritter aa06ab1e25 Add nullability annotations to tests in module/spring-boot-data-neo4j
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter 09967b1a5d Add nullability annotations to tests in module/spring-boot-data-mongodb
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter 5c0d2ee180 Add nullability annotations to tests in module/spring-boot-data-ldap
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter bb19585601 Add nullability annotations to tests in module/spring-boot-data-jpa
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter f2c2d19a9c Add nullability annotations to tests in module/spring-boot-data-jdbc
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter 3db8b5fb26 Add nullability annotations to tests in module/spring-boot-data-elasticsearch
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter e313624263 Add nullability annotations to tests in module/spring-boot-data-couchbase
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter af2436de84 Add nullability annotations to tests in module/spring-boot-data-commons
See gh-47263
2025-10-02 15:35:05 +02:00
Moritz Halbritter 4a62872d63 Add nullability annotations to tests in module/spring-boot-data-cassandra
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter f5d6bea934 Add nullability annotations to tests in module/spring-boot-couchbase
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter 419d78b359 Add nullability annotations to tests in module/spring-boot-cloudfoundry
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter b6950f8fb0 Add nullability annotations to tests in module/spring-boot-cassandra
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter f8ce17c751 Add nullability annotations to tests in module/spring-boot-cache
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter 4a30228978 Add nullability annotations to tests in module/spring-boot-batch
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter f3df45ace1 Add nullability annotations to tests in module/spring-boot-artemis
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter 3aaf4b7b0a Add nullability annotations to tests in module/spring-boot-amqp
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter 4af0d6d747 Add nullability annotations to tests in module/spring-boot-actuator-autoconfigure
See gh-47263
2025-10-02 15:35:04 +02:00
Moritz Halbritter 3c3726b89e Improve null-safety of module/spring-boot-actuator-autoconfigure
See gh-47263
2025-10-02 15:35:03 +02:00
Brian Clozel 92ee73df30 Deprecate HttpMessageConverters for Framework's
Prior to this commit, Spring Boot had an  `HttpMessageConverters` class
that allowed, to configure message converter instances for MVC server
applications and traditional Spring HTTP clients.

As of Spring Framework 7.0, Framework ships its own
`HttpMessageConverters` class, aligning with the existing codecs
configuration on the WebFlux side. As a result, a few methods taking
`List<HttpMessageConverter>` as arguments were deprecated in favor of
the new arrangement.

This commit adapts to the Framework changes by deprecating Boot's
`HttpMessageConverters` in favor of Framework's. This splits the client
and server configuration as they are meant to be managed separately.
Applications can still contribute `HttpMessageConverters` (Boot's
variant) beans but the type itself is now deprecated.
Instead, applications should now contribute
`ClientHttpMessageConvertersCustomizer` and
`ServerHttpMessageConvertersCustomizer` beans to customize message
converters.

Closes gh-46411
2025-10-02 15:22:13 +02:00
Moritz Halbritter 418e057afc Add nullability annotations to tests in core/spring-boot
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: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:false version:24], 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
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: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
See gh-47263
2025-10-02 14:34:34 +02:00
Moritz Halbritter 1fda419b17 Upgrade to NullAway 0.12.10 and ErrorProne 2.42.0
See gh-47263
2025-10-02 14:34:33 +02:00
Moritz Halbritter 4c8cabcb3a Upgrade to JUnit Jupiter 6.0.0
Closes gh-47383
2025-10-02 14:20:04 +02:00
Moritz Halbritter dec46b45d7 Start building against Spring Framework 7.0.0-RC1 snapshots
See gh-47382
2025-10-02 14:17:29 +02:00
Moritz Halbritter 57992512b7 Add nullability annotations to tests in core/spring-boot-autoconfigure
See gh-47263
2025-10-02 12:17:57 +02:00
Moritz Halbritter b566b73be6 Add nullability annotations to tests in core/spring-boot-docker-compose
See gh-47263
2025-10-02 12:17:00 +02:00
Moritz Halbritter 532ea9abc1 Add nullability annotations to tests in core/spring-boot-properties-migrator
See gh-47263
2025-10-02 12:16:24 +02:00
Moritz Halbritter ea05f6df15 Add nullability annotations to tests in core/spring-boot-test
See gh-47263
2025-10-02 12:12:44 +02:00
Moritz Halbritter 23c9b6510b Add nullability annotations to tests in core/spring-boot-testcontainers
See gh-47263
2025-10-02 12:00:16 +02:00
Moritz Halbritter 9bb62a074b Add nullability annotations to tests in module/spring-boot-actuator
See gh-47263
2025-10-02 11:59:32 +02:00
Moritz Halbritter fe975214cd Add nullability annotations to tests in module/spring-boot-activemq
See gh-47263
2025-10-02 11:58:23 +02:00
Moritz Halbritter c099462e6f Upgrade to nullability plugin 0.0.5
Closes gh-47380
2025-10-02 11:43:11 +02:00
Andy Wilkinson ee2730ca8d Stop an ObjectMapper from causing JsonMapper auto-config to back off
Previously, the auto-configured JsonMapper would back off when any
type of ObjectMapper was defined. Updating this was missed as part
of the move to Jackson 3 where both Boot and Framework now intend to
use the more specific JsonMapper type.

This commit updates the condition such that a JsonMapper will still
be auto-configured when any other type of ObjectMapper is definied.
It will now only back off when a JsonMapper bean is defined.

Closes gh-47379
2025-10-02 09:30:26 +01:00
Stéphane Nicoll b28d390c69 Rationalize SSL bundles in RedisConnectionDetails
This commit exposes a single ssl bundle rather than a specific bundle
for each of the three supported modes.

Closes gh-47375
2025-10-02 10:00:07 +02:00
Stéphane Nicoll e7ffa33d65 Remove unused file 2025-10-02 09:44:38 +02:00
Phillip Webb dadfd9a35d Add classic test starter
See gh-46356
See gh-47322
2025-10-01 21:55:38 -07:00
Phillip Webb 2d312ed5f5 Add remaining test starters
Add test starters for all remaining non-deprecated starters.

See gh-46356
See gh-47322
2025-10-01 21:55:33 -07:00
Phillip Webb ee72caf7dc Drop `spring-boot-rest-client-test` dependency from test starter
See gh-46356
See gh-47322
2025-10-01 21:55:25 -07:00
Phillip Webb a30e832915 Add starters for corresponding test modules
See gh-46356
See gh-47322
2025-10-01 21:55:19 -07:00
Phillip Webb 0ae23de2b5 Refine test module dependencies
See gh-46356
See gh-47322
2025-10-01 21:55:14 -07:00
Phillip Webb 2a521ce4e9 Remove `spring-boot-web-server-test` module
Remove the `spring-boot-web-server-test` module, adding
`SpringBootTestRandomPortContextCustomizerFactory` to
`spring-boot-web-server` as a replacement for
`SpringBootTestRandomPortApplicationListener`.

See gh-46356
See gh-47322
2025-10-01 21:54:54 -07:00
Phillip Webb 3cced515ce Remove unused HTML Unit classes
Remove `LocalHostWebClient` and `LocalHostWebConnectionHtmlUnitDriver`
in favor of `BaseUrl` versions.

See gh-46356
See gh-47322
2025-10-01 21:54:44 -07:00
Phillip Webb 279de9e807 Migrate to `BaseUrlUriTemplateHandler`
Remove `LocalHostUriTemplateHandler` and migrate existing code to use
`BaseUrlUriTemplateHandler`.

See gh-46356
See gh-47322
2025-10-01 21:54:32 -07:00
Phillip Webb 97c89b480f Move `@LocalServerPort` and `@LocalManagementServerPort`
Move `@LocalServerPort` and `@LocalManagementServerPort` back to
`spring-boot-test`. The should help reduce upgrade pain since these
annotations are fairly commonly used. It also removes the need for
depending on `spring-boot-webserver-test`.

This is slight compromise with the module structure, since the
web-server module usually contributes the properties referenced
by the annotations.

See gh-46356
See gh-47322
2025-10-01 21:53:58 -07:00
Phillip Webb 82795f9966 Move `DisableReactorResourceFactory...` to spring-boot-test
Move `DisableReactorResourceFactoryGlobalResources...` support from
`spring-boot-web-server-test` back to `spring-boot-test` since it's
useful if Reactor Netty is being used directly and removes the need
for the `spring-boot-web-server-test` dependency.

See gh-46356
See gh-47322
2025-10-01 21:53:35 -07:00
Phillip Webb 7c8a15629b Remove `spring-boot-web-server-test` usage
Remove `spring-boot-web-server-test` usage from the
`spring-boot-webflux-test` module.

See gh-46356
See gh-47322
2025-10-01 21:52:55 -07:00
Phillip Webb ef37765625 Add `BaseUrl` backed HTTP Unit support classes
Add new HTML Unit support classes that use `BaseUrlProviders`
to find the `BaseUrl`.

See gh-46356
2025-10-01 21:51:58 -07:00
Phillip Webb bba56ffc8b Move `RestTestClientBuilderCustomizer` to `spring-boot-test`
Relocate `RestTestClientBuilderCustomizer` to `spring-boot-test`
and break the direct link to web-server by making use of
`spring.factories` and the new `BaseUrlProviders` class.

See gh-46356
2025-10-01 21:51:20 -07:00
Phillip Webb 6f909114e7 Move `WebTestClientBuilderCustomizer` to `spring-boot-test`
Relocate `WebTestClientBuilderCustomizer` to `spring-boot-test`
and break the direct link to web-server and http-codec by making
use of `spring.factories` and the new `BaseUrlProviders` class.

A new `spring-boot-test-integration-test` module has also been
added to ensure hold the previous tests.

See gh-46356
2025-10-01 21:50:13 -07:00
Phillip Webb 79091f926d Introduce `BaseUrl` and `BaseUrlProvider`
Add the concept of a `BaseUrl` to the core `spring-boot-test`
module for use when making test HTTP calls. The web server module
provides `BaseUrlProvider` implementations that provide the actual
base URL (usually `https://localhost:<local-server-port>`).

Test utilities will be able to use `BaseUrlProviders` to find the
`BaseUrl`.

See gh-46356
2025-10-01 21:46:28 -07:00
Phillip Webb 155e3bd5e6 Relocate `@AutoConfigureDataSourceInitialization`
Relocate `@AutoConfigureDataSourceInitialization` from
`spring-jdbc-test` to `spring-boot-test-autoconfigure`. This change
allows Flyway and Liquibase to respond to the annotation without
the user needing to remember the `spring-jdbc-test` dependency.

This is especially important for R2DB applications which may
still be using Flyway or Liquibase for migrations and will
want them to apply during tests.

See gh-46356
See gh-47322
2025-10-01 21:43:13 -07:00
Phillip Webb 8008076e04 Remove spring-boot-json-test module
Remove spring-boot-json-test module and spread code between
`spring-boot-test`, `spring-boot-test-autoconfigure` and JSON
technology modules.

See gh-46356
See gh-47322
2025-10-01 21:42:18 -07:00
Phillip Webb 4b2d358384 Refine spring-boot-test-autoconfigure dependencies
Make `spring-boot-test-autoconfigure` optionally depend on
`spring-boot-autoconfigure` so that it can be an `api` dependency
for `*-test` modules. Also relocate it to core.

See gh-47322
2025-10-01 21:41:55 -07:00
Phillip Webb 17e655b7e5 Relocate `@PropertyMapping` to spring-boot-test
Move `@PropertyMapping` and supporting code from the
`spring-boot-test-autoconfigure` module to `spring-boot-test`
since it's generally applicable.

See gh-46356
See gh-47322
2025-10-01 21:41:03 -07:00
Phillip Webb 2b3a8ff647 Relocate `@TypeExcludeFilters` to spring-boot-test
Move `@TypeExcludeFilters` and supporting code from the
`spring-boot-test-autoconfigure` module to `spring-boot-test`
since it's generally applicable.

See gh-46356
See gh-47322
2025-10-01 21:39:34 -07:00
Phillip Webb 36732bd74a Polish 2025-10-01 17:21:00 -07:00
Phillip Webb 352925bbe8 Polish @Since tags 2025-10-01 17:10:30 -07:00
Phillip Webb f8f6e59d1a Polish starter descriptions 2025-10-01 11:40:03 -07:00
Phillip Webb 08a641c1a2 Polish whitespace in gradle files 2025-10-01 11:40:03 -07:00
Andy Wilkinson 26364c27e2 Rename …DataAutoConfiguration to Data…AutoConfiguration
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: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:false version:24], 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
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: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-47049
2025-10-01 17:39:08 +01:00
Stéphane Nicoll 787840735b Add support for RestTestClient
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: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:false version:24], 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
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: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 adds support for RestTestClient for MockMvc and integration
tests.

Closes gh-47335
2025-10-01 09:04:59 +02:00
Andy Wilkinson e2ba4dad2a Correct property in Session Data Redis smoke test
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: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:false version:24], 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
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: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-09-30 17:03:55 +01:00
Andy Wilkinson 7a595f1b83 Rename properties for Spring Session Data MongoDB and Data Redis
Closes gh-47333
2025-09-30 15:46:46 +01:00
Andy Wilkinson 922592938a Polish 2025-09-30 15:34:37 +01:00
Andy Wilkinson b23d7fe203 Ignore deprecation warning caused by Framework
See gh-45501
See spring-projects/spring-framework#35557
2025-09-30 14:49:47 +01:00
Andy Wilkinson f9d4589259 Use Java 25 in native image system test
We need to use Java 25 when using buildpacks to create a native image
for a couple of reasons:

- Framework has raised its GraalVM baseline to 25
- Buildpacks have removed support for Java 24

See gh-45501
2025-09-30 13:02:24 +01:00
Stéphane Nicoll d4fce9a068 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: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:false version:24], 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
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: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-47363
2025-09-30 08:07:01 +02:00
Stéphane Nicoll cc20b3ec3b 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: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
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
Closes gh-47362
2025-09-30 08:06:54 +02:00
Stéphane Nicoll f28bea16c5 Merge pull request #47356 from dependabot[bot]
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
* pr/47356:
  Bump patch-package from 8.0.0 to 8.0.1 in /antora

Closes gh-47356
2025-09-30 08:06:42 +02:00
dependabot[bot] 4ba14c139e Bump patch-package from 8.0.0 to 8.0.1 in /antora
Bumps [patch-package](https://github.com/ds300/patch-package) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/ds300/patch-package/releases)
- [Changelog](https://github.com/ds300/patch-package/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ds300/patch-package/commits)

---
updated-dependencies:
- dependency-name: patch-package
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

See gh-47356

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-30 08:05:57 +02:00
Stéphane Nicoll ad3a18d086 Merge branch '3.5.x'
Closes gh-47361
2025-09-30 07:54:40 +02:00
Stéphane Nicoll 98b4afe527 Merge branch '3.4.x' into 3.5.x
Closes gh-47360
2025-09-30 07:54:32 +02:00
Stéphane Nicoll a8caeed578 Merge pull request #47357 from dependabot[bot]
* pr/47357:
  Polish "Bump gradle/actions from 4.4.3 to 4.4.4"
  Bump gradle/actions from 4.4.3 to 4.4.4

Closes gh-47357
2025-09-30 07:54:25 +02:00
Stéphane Nicoll bc968fc671 Polish "Bump gradle/actions from 4.4.3 to 4.4.4"
See gh-47357
2025-09-30 07:54:12 +02:00
dependabot[bot] 1c1a35f6be Bump gradle/actions from 4.4.3 to 4.4.4
Bumps [gradle/actions](https://github.com/gradle/actions) from 4.4.3 to 4.4.4.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](ed408507ea...748248ddd2)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: 4.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

See gh-47357

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-30 07:53:49 +02:00
Stéphane Nicoll eb307b91ec Merge branch '3.5.x'
Closes gh-47359
2025-09-30 07:50:09 +02:00
Stéphane Nicoll 14791f0593 Fix typos
Closes gh-47358
2025-09-30 07:49:16 +02:00
Stéphane Nicoll 474c9cdeb1 Fix javadoc links in reference guide
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: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:false version:24], 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
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: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-47351
2025-09-29 18:37:31 +02:00
Stéphane Nicoll cbdd7cf23b Fix links to source code in reference documentation
Closes gh-47348
2025-09-29 16:38:04 +02:00
Andy Wilkinson 569fa5fd7d Remove milestone repository from Maven and Gradle examples
Closes gh-47341
2025-09-29 15:25:02 +01:00
Stéphane Nicoll 5a2f90d1f1 Register spring-boot-batch-jdbc for configuration metadata changelog
See gh-46307
2025-09-29 15:36:04 +02:00
Stéphane Nicoll 5301c8d905 Use new spring-boot-micrometer-* modules consistently
Closes gh-47350
2025-09-29 15:34:46 +02:00
Stéphane Nicoll 4f6bbac13e Add support for in-memory Batch infrastructure
This commit moves the existing JDBC-based Spring Batch infrastructure
to a new 'spring-boot-batch-jdbc' module, while the existing module
only offers in-memory (aka resourceless) support.

The commit also updates the reference guide to provide some more
information about what's available and how to use it.

Closes gh-46307
2025-09-29 15:00:52 +02:00
Andy Wilkinson 54ffc42309 Fix table formatting
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: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:false version:24], 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
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: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-47345
See gh-47328
2025-09-29 10:47:41 +01:00
Stéphane Nicoll 8c5a25ee5c Merge branch '3.5.x'
Closes gh-47347
2025-09-29 10:23:29 +02:00
Stéphane Nicoll 30d3889079 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: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
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-47346
2025-09-29 10:22:13 +02:00
Stéphane Nicoll e8b6ab14bc Merge pull request #47300 from xyraclius
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/47300:
  Polish "Use liquibase schema in LiquibaseEndpoint if it set"
  Use liquibase schema in LiquibaseEndpoint if it set

Closes gh-47300
2025-09-29 10:22:01 +02:00
Stéphane Nicoll 5344fb218a Polish "Use liquibase schema in LiquibaseEndpoint if it set"
See gh-47300
2025-09-29 10:16:16 +02:00
Nabil Fawwaz Elqayyim bdb05639bc Use liquibase schema in LiquibaseEndpoint if it set
See gh-47300

Signed-off-by: Nabil Fawwaz Elqayyim <master@nabilfawwaz.com>
2025-09-29 10:16:05 +02:00
Moritz Halbritter db10e3d1ed Fix typo 2025-09-29 10:11:08 +02:00
Stéphane Nicoll ae86895953 Merge branch '3.5.x'
Closes gh-47344
2025-09-29 09:46:15 +02:00
Stéphane Nicoll 93c9413ac0 Merge branch '3.4.x' into 3.5.x
Closes gh-47343
2025-09-29 09:46:07 +02:00
Stéphane Nicoll f93c43cb8a Merge pull request #47339 from fhiyo
* pr/47339:
  Polish "Use non-deprecated syntax to configure sourceCompatibility"
  Use non-deprecated syntax to configure sourceCompatibility

Closes gh-47339
2025-09-29 09:46:02 +02:00
Stéphane Nicoll c3aca4b126 Polish "Use non-deprecated syntax to configure sourceCompatibility"
See gh-47339
2025-09-29 09:42:16 +02:00
fhiyo b3db525f0f Use non-deprecated syntax to configure sourceCompatibility
See gh-47339

Signed-off-by: fhiyo <13327262+fhiyo@users.noreply.github.com>
2025-09-29 09:42:04 +02:00
Andy Wilkinson 52c55788a2 Add new -test modules to spring-boot-dependencies
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: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:false version:24], 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
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: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
See gh-47322
See gh-46356
2025-09-26 17:57:18 +01:00
Andy Wilkinson 990644919a Make all TypeExcludeFilters package-private
Closes gh-47227
2025-09-26 11:08:53 +01:00
Andy Wilkinson 2756424035 Merge branch '3.5.x'
Closes gh-47331
2025-09-26 10:32:41 +01:00
Andy Wilkinson 9c727be8f2 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: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
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-47330
2025-09-26 10:31:02 +01:00
Andy Wilkinson e4e3988433 Fix link to Framework's @Bean annotation
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-47329
2025-09-26 10:29:25 +01:00
Andy Wilkinson 0959271061 Move jackson read and write to spring.jackson.json
The spring.jackson.read and spring.jackson.write properties are
JSON-specific. To make this more clear, this commit moves them
beneath spring.jackson.json. This also paves the way for
spring.jackson.cbor and spring.jackson.xml properties for CBOR- and
XML-specific settings should we add auto-configuration for XMLMapper
and/or CBORMapper in the future.

Closes gh-47328
2025-09-26 10:01:59 +01:00
Andy Wilkinson 8c7e0c675f Move Jackson datetime property beneath datatype
Closes gh-47327
2025-09-26 09:04:06 +01:00
Andy Wilkinson 0b601118bd Modularize spring-boot-test
Closes gh-46356
2025-09-25 17:24:12 +01:00
Andy Wilkinson 5348880b69 Modularize spring-boot-test-autoconfigure
This commit modularizes spring-boot-test-autoconfigure. It now
contains only the code that's central to test auto-configuration.
Feature-specific functionality has moved out into -test modules,
some existing and some newly created. For example, `@DataJpaTest` can
now be found in spring-boot-data-jpa-test.

Closes gh-47322
2025-09-25 13:11:35 +01:00
Andy Wilkinson 7979a51f65 Fix Maven Plugin tests on main
See gh-47318
See gh-47319
2025-09-25 08:47:39 +01:00
Phillip Webb 27715dee20 Allow jars to be marked as a development-tool to exclude from uber-jar
Closes gh-47320
2025-09-24 16:38:44 -07:00
Phillip Webb d27aedf92a Switch Maven plugin to exclude optional dependencies by default
Closes gh-47318
2025-09-24 16:34:19 -07:00
Phillip Webb b3c28f1ef3 Merge branch '3.5.x'
Closes gh-47319
2025-09-24 16:32:14 -07:00
Phillip Webb f3b44031a6 Support exclusion of optional dependencies in uber-jars
Update Maven plugin with `<includeOptional>` configuration property that
can be used to toggle if optional dependencies are packages.

For back-compatibility, in 3.5.x the default is `true`.

Fixes gh-25403
2025-09-24 16:27:32 -07:00
Phillip Webb f6da5e7a5c Merge branch '3.5.x' 2025-09-24 16:22:44 -07:00
Phillip Webb 8d63043d9e Merge branch '3.4.x' into 3.5.x 2025-09-24 16:20:42 -07:00
Phillip Webb b43d2f2088 Remove version number from assertions 2025-09-24 14:08:26 -07:00
Andy Wilkinson 0b0b742758 Merge branch '3.5.x'
Closes gh-47312
2025-09-24 15:21:40 +01:00
Andy Wilkinson b61e38bef8 Support launching with a parameterless main method
Fixes gh-47311
2025-09-24 15:16:18 +01:00
Andy Wilkinson 6490b749db Merge branch '3.5.x'
Closes gh-47310
2025-09-24 14:57:27 +01:00
Andy Wilkinson 9a1d9f677b Add support for finding package-private and parameterless main
Fixes gh-47309
2025-09-24 14:54:06 +01:00
Brian Clozel 1cd14c96a5 Configure ProblemDetailJacksonMixin on JsonMapper
Prior to this commit, Spring Boot would use Framework's
`Jackson2ObjectMapperBuilder` to configure the `ObjectMapper` instance.
This builder would configure the `ProblemDetail` mixin automatically.

With the introduction of Jackson 3.x support, Spring Framework removed
its builder in favor of the native Jackson builder. As a result, the
mixin is not registered with the `JsonMapper` aymore.

This commit ensures that the mixin is registered if the `ProblemDetail`
class is present in the classpath.

Closes gh-47298
2025-09-24 14:29:09 +02:00
Andy Wilkinson 51b606e941 Polish 2025-09-24 12:47:09 +01:00
Stéphane Nicoll c5e28c9133 Upgrade to Log4j2 2.25.2
Closes gh-46334
2025-09-24 12:52:00 +02:00
Stéphane Nicoll c4cace3f74 Upgrade to Log4j2 2.25.2
See gh-46334
2025-09-24 12:14:32 +02:00
Stéphane Nicoll b7695200a9 Re-apply the upgrade to Log4j2 2.25.1
See gh-46372
See gh-46334
2025-09-24 12:13:54 +02:00
Stéphane Nicoll 5cec09dd02 Merge pull request #47297 from rstoyanchev
* pr/47297:
  Polish
  Fix renamed link to HTTP Service Clients docs

Closes gh-47297
2025-09-24 11:56:05 +02:00
Stéphane Nicoll cae5a811ad Polish
See gh-47297
2025-09-24 11:48:26 +02:00
rstoyanchev 0afd40fa40 Fix renamed link to HTTP Service Clients docs
See gh-47297
2025-09-24 11:44:47 +02:00
Stéphane Nicoll 3265a2672d Merge branch '3.5.x'
Closes gh-47307
2025-09-24 11:43:34 +02:00
Stéphane Nicoll b6a1c29763 Merge branch '3.4.x' into 3.5.x
Closes gh-47306
2025-09-24 11:43:21 +02:00
Stéphane Nicoll 9a3a3b1b5e Merge pull request #47304 from scottfrederick
* pr/47304:
  Update managed dependency version override examples in documentation

Closes gh-47304
2025-09-24 11:43:10 +02:00
Scott Frederick 6354d802c0 Update managed dependency version override examples in documentation
The examples for overriding a managed dependency version with Maven
were using an outdated version property. This commit updates the
example to use a valid property.

The version override warning from the Gradle plugin docs was also
copied to the Maven docs.

See gh-47304

Signed-off-by: Scott Frederick <scottyfred@gmail.com>
2025-09-24 11:39:49 +02:00
Phillip Webb bc46bb2a24 Drop spring-boot-loader-classic support
Closes gh-45714
2025-09-23 15:31:51 -07:00
Phillip Webb 3b2c8abf50 Restructure buildpack docker package
Closes gh-45284
2025-09-23 13:59:27 -07:00
Phillip Webb dc341edfdd Add config prop to enabled/disable Elasticsearch sniffer
Closes gh-47301

Co-Authored-By: Andy Wilkinson <andy.wilkinson@broadcom.com>
2025-09-23 08:28:51 +01:00
Phillip Webb 3a9ab15696 Reintroduce previous EnvironmentPostProcessor in deprecated form
Restore previous `EnvironmentPostProcessor` in deprecated form to help
lessen upgrade pain.

Closes gh-47272
2025-09-22 11:25:23 -07:00
Andy Wilkinson 8d87586395 Merge branch '3.5.x'
Closes gh-47296
2025-09-22 11:05:13 +01:00
Andy Wilkinson d3bab5f82d Test against Gradle 9.1.0
Closes gh-47295
2025-09-22 11:02:55 +01:00
Phillip Webb 862db41134 Fix typo 2025-09-19 15:09:40 -07:00
Stéphane Nicoll 42cc7775f4 Merge branch '3.5.x'
Closes gh-47283
2025-09-19 17:57:10 +02:00
Stéphane Nicoll 5c95ee798c Use Java 25 GA on CI
Closes gh-47246
2025-09-19 17:56:49 +02:00
Stéphane Nicoll 14703cbafd Revert "Remove mentions of JUnit 4"
This reverts commit 3b98af30f5.

See gh-47228
2025-09-19 17:05:00 +02:00
Stéphane Nicoll 3b98af30f5 Remove mentions of JUnit 4
This commit removes all mentions of JUnit 4 from the Javadoc and
reference documentation. It also harmonizes to simply refers to JUnit.

Closes gh-47228
2025-09-19 15:29:11 +02:00
Moritz Halbritter 8d000e008f Merge branch '3.5.x' 2025-09-19 11:24:32 +02:00
Moritz Halbritter 335a0b76b5 Merge branch '3.4.x' into 3.5.x
Closes gh-47275
2025-09-19 10:38:39 +02:00
Moritz Halbritter 4a1de8534f Add detection for Bitnami Legacy images
This commit also adjusts the tests to use bitnamilegacy images because we have no way to test against the original bitnami images.

Closes gh-46983
2025-09-19 10:18:59 +02:00
Moritz Halbritter 630bb335ea Revert "Disable tests which use Bitnami images"
This reverts commit 24a23c4f72.

See gh-46983
2025-09-19 09:01:01 +02:00
Phillip Webb c1d51f8687 Remove Bitnami support
Closes gh-47267
2025-09-18 14:41:16 -07:00
Phillip Webb 255ea92a57 Add `HttpClientTransport` factory support
Update `JettyClientHttpRequestFactoryBuilder` and
`JettyClientHttpConnectorBuilder` with support for create the
`HttpClientTransport` from a factory function.

Closes gh-47251
2025-09-18 14:02:18 -07:00
Phillip Webb b01dc92233 Add spring-boot-persistence to dependencies POM
Fixes gh-47271
2025-09-18 13:34:22 -07:00
Phillip Webb 2cf854c5b6 Polish 2025-09-18 13:29:47 -07:00
2358 changed files with 22768 additions and 22088 deletions

View File

@ -23,7 +23,7 @@ inputs:
java-version:
description: 'Java version to use for the build'
required: false
default: '24'
default: '25'
runs:
using: composite
steps:
@ -42,12 +42,12 @@ runs:
${{ inputs.java-toolchain == 'true' && '24' || '' }}
- name: Set Up Gradle With Read/Write Cache
if: ${{ inputs.cache-read-only == 'false' }}
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4
with:
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4
with:
develocity-access-key: ${{ inputs.develocity-access-key }}
develocity-token-expiry: 4

View File

@ -21,7 +21,7 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@88e9eba31c07e31beefa4cef5c0e93d1af9535d7 # v4.6.1
uses: jfrog/setup-jfrog-cli@c32bf10843e4071112c4ea3abf622d3b27cd8c17 # v4.7.0
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Artifacts

View File

@ -17,7 +17,7 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@88e9eba31c07e31beefa4cef5c0e93d1af9535d7 # v4.6.1
uses: jfrog/setup-jfrog-cli@c32bf10843e4071112c4ea3abf622d3b27cd8c17 # v4.7.0
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Release Artifacts

View File

@ -23,16 +23,13 @@ jobs:
toolchain: true
- version: 21
toolchain: true
- version: 24
toolchain: false
- version: 25
early-access: true
toolchain: true
toolchain: false
exclude:
- os:
name: Linux
java:
version: 24
version: 25
- os:
name: ${{ github.repository == 'spring-projects/spring-boot-commercial' && 'Windows' }}
steps:

View File

@ -75,7 +75,7 @@ jobs:
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@88e9eba31c07e31beefa4cef5c0e93d1af9535d7 # v4.6.1
uses: jfrog/setup-jfrog-cli@c32bf10843e4071112c4ea3abf622d3b27cd8c17 # v4.7.0
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build

View File

@ -86,7 +86,7 @@ jobs:
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@88e9eba31c07e31beefa4cef5c0e93d1af9535d7 # v4.6.1
uses: jfrog/setup-jfrog-cli@c32bf10843e4071112c4ea3abf622d3b27cd8c17 # v4.7.0
env:
JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote open source build

View File

@ -59,7 +59,7 @@ jobs:
with:
stable: true
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4
with:
cache-read-only: false
- name: Configure Gradle Properties

View File

@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=24.0.2-librca
java=25-librca

View File

@ -14,7 +14,7 @@
"@springio/antora-xref-extension": "1.0.0-alpha.4",
"@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.8",
"@springio/asciidoctor-extensions": "1.0.0-alpha.17",
"patch-package": "^8.0.0"
"patch-package": "^8.0.1"
}
},
"node_modules/@antora/asciidoc-loader": {
@ -575,14 +575,6 @@
"resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
"integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@ -1406,17 +1398,17 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"license": "MIT",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=10"
"node": ">=12"
}
},
"node_modules/fs-mkdirp-stream": {
@ -1993,9 +1985,10 @@
}
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
},
@ -2331,38 +2324,30 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/patch-package": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz",
"integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz",
"integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==",
"license": "MIT",
"dependencies": {
"@yarnpkg/lockfile": "^1.1.0",
"chalk": "^4.1.2",
"ci-info": "^3.7.0",
"cross-spawn": "^7.0.3",
"find-yarn-workspace-root": "^2.0.0",
"fs-extra": "^9.0.0",
"fs-extra": "^10.0.0",
"json-stable-stringify": "^1.0.2",
"klaw-sync": "^6.0.0",
"minimist": "^1.2.6",
"open": "^7.4.2",
"rimraf": "^2.6.3",
"semver": "^7.5.3",
"slash": "^2.0.0",
"tmp": "^0.0.33",
"tmp": "^0.2.4",
"yaml": "^2.2.2"
},
"bin": {
@ -2750,18 +2735,6 @@
"node": ">= 0.10"
}
},
"node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -3118,14 +3091,12 @@
}
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
"license": "MIT",
"engines": {
"node": ">=0.6.0"
"node": ">=14.14"
}
},
"node_modules/to-absolute-glob": {
@ -3238,6 +3209,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"license": "MIT",
"engines": {
"node": ">= 10.0.0"
}

View File

@ -12,7 +12,7 @@
"@springio/antora-zip-contents-collector-extension": "1.0.0-alpha.8",
"@asciidoctor/tabs": "1.0.0-beta.6",
"@springio/asciidoctor-extensions": "1.0.0-alpha.17",
"patch-package": "^8.0.0"
"patch-package": "^8.0.1"
},
"config": {
"ui-bundle-url": "https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.18/ui-bundle.zip"

View File

@ -80,7 +80,6 @@ tasks.register("integrationTest") {
ant.propertyref(name: "ivy.class.path")
}
plainlistener()
file(layout.buildDirectory.dir("test-results/integrationTest")).mkdirs()
xmllistener(toDir: resultsDir)
fileset(dir: layout.buildDirectory.dir("it").get().asFile.toString(), includes: "**/build.xml")
}

View File

@ -141,9 +141,13 @@ final class ApplicationPluginAction implements PluginApplicationAction {
}
}
@SuppressWarnings("deprecation")
private void configureFileMode(CopySpec copySpec, int mode) {
copySpec.setFileMode(mode);
try {
copySpec.getClass().getMethod("setFileMode", Integer.class).invoke(copySpec, Integer.valueOf(mode));
}
catch (Exception ex) {
throw new RuntimeException("Failed to set file mode on CopySpec", ex);
}
}
}

View File

@ -17,7 +17,6 @@
package org.springframework.boot.gradle.plugin;
import java.io.File;
import java.util.Collections;
import java.util.Set;
import java.util.jar.JarFile;
@ -33,7 +32,7 @@ import org.gradle.api.specs.Spec;
*/
class JarTypeFileSpec implements Spec<File> {
private static final Set<String> EXCLUDED_JAR_TYPES = Collections.singleton("dependencies-starter");
private static final Set<String> EXCLUDED_JAR_TYPES = Set.of("dependencies-starter", "development-tool");
@Override
public boolean isSatisfiedBy(File file) {

View File

@ -285,7 +285,6 @@ final class JavaPluginAction implements PluginApplicationAction {
private void configureProductionRuntimeClasspathConfiguration(Project project) {
Configuration productionRuntimeClasspath = project.getConfigurations()
.create(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME);
productionRuntimeClasspath.setVisible(false);
Configuration runtimeClasspath = project.getConfigurations()
.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
productionRuntimeClasspath.attributes((attributes) -> {

View File

@ -104,7 +104,6 @@ class WarPluginAction implements PluginApplicationAction {
.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));
bootWar.resolvedArtifacts(runtimeClasspath.getIncoming().getArtifacts().getResolvedArtifacts());
});
bootWarProvider.map(War::getClasspath);
return bootWarProvider;
}

View File

@ -43,7 +43,7 @@ import org.springframework.util.Assert;
* @since 3.0.0
*/
@CacheableTask
public class ProcessTestAot extends AbstractAot {
public abstract class ProcessTestAot extends AbstractAot {
private @Nullable FileCollection classpathRoots;

View File

@ -34,8 +34,6 @@ import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.loader.tools.LoaderImplementation;
/**
* A Spring Boot "fat" archive task.
*
@ -137,15 +135,6 @@ public interface BootArchive extends Task {
*/
void resolvedArtifacts(Provider<Set<ResolvedArtifactResult>> resolvedArtifacts);
/**
* The loader implementation that should be used with the archive.
* @return the loader implementation
* @since 3.2.0
*/
@Input
@Optional
Property<LoaderImplementation> getLoaderImplementation();
/**
* Returns whether the JAR tools should be included as a dependency in the layered
* archive.

View File

@ -22,32 +22,24 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import org.gradle.api.file.ConfigurableFilePermissions;
import org.gradle.api.file.CopySpec;
import org.gradle.api.file.FileCopyDetails;
import org.gradle.api.file.FileTreeElement;
import org.gradle.api.file.RelativePath;
import org.gradle.api.internal.file.copy.CopyAction;
import org.gradle.api.internal.file.copy.CopyActionProcessingStream;
import org.gradle.api.internal.file.copy.FileCopyDetailsInternal;
import org.gradle.api.java.archives.Attributes;
import org.gradle.api.java.archives.Manifest;
import org.gradle.api.provider.Property;
import org.gradle.api.specs.Spec;
import org.gradle.api.specs.Specs;
import org.gradle.api.tasks.WorkResult;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.util.PatternSet;
import org.gradle.util.GradleVersion;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.loader.tools.LoaderImplementation;
/**
* Support class for implementations of {@link BootArchive}.
*
@ -123,13 +115,11 @@ class BootArchiveSupport {
return (version != null) ? version : "unknown";
}
CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies,
LoaderImplementation loaderImplementation, boolean supportsSignatureFile) {
return createCopyAction(jar, resolvedDependencies, loaderImplementation, supportsSignatureFile, null, null);
CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies, boolean supportsSignatureFile) {
return createCopyAction(jar, resolvedDependencies, supportsSignatureFile, null, null);
}
CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies,
LoaderImplementation loaderImplementation, boolean supportsSignatureFile,
CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies, boolean supportsSignatureFile,
@Nullable LayerResolver layerResolver, @Nullable String jarmodeToolsLocation) {
File output = jar.getArchiveFile().get().getAsFile();
Manifest manifest = jar.getManifest();
@ -145,9 +135,8 @@ class BootArchiveSupport {
String encoding = jar.getMetadataCharset();
CopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, dirPermissions,
filePermissions, includeDefaultLoader, jarmodeToolsLocation, requiresUnpack, exclusions, launchScript,
librarySpec, compressionResolver, encoding, resolvedDependencies, supportsSignatureFile, layerResolver,
loaderImplementation);
return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action;
librarySpec, compressionResolver, encoding, resolvedDependencies, supportsSignatureFile, layerResolver);
return action;
}
private @Nullable Integer getUnixNumericDirPermissions(CopySpec copySpec) {
@ -164,14 +153,22 @@ class BootArchiveSupport {
return permissions.isPresent() ? permissions.get().toUnixNumeric() : null;
}
@SuppressWarnings("deprecation")
private @Nullable Integer getDirMode(CopySpec copySpec) {
return copySpec.getDirMode();
try {
return (Integer) copySpec.getClass().getMethod("getDirMode").invoke(copySpec);
}
catch (Exception ex) {
throw new RuntimeException("Failed to get dir mode from CopySpec", ex);
}
}
@SuppressWarnings("deprecation")
private @Nullable Integer getFileMode(CopySpec copySpec) {
return copySpec.getFileMode();
try {
return (Integer) copySpec.getClass().getMethod("getFileMode").invoke(copySpec);
}
catch (Exception ex) {
throw new RuntimeException("Failed to get file mode from CopySpec", ex);
}
}
private boolean isUsingDefaultLoader(Jar jar) {
@ -234,26 +231,4 @@ class BootArchiveSupport {
details.setRelativePath(details.getRelativeSourcePath());
}
/**
* {@link CopyAction} variant that sorts entries to ensure reproducible ordering.
*/
private static final class ReproducibleOrderingCopyAction implements CopyAction {
private final CopyAction delegate;
private ReproducibleOrderingCopyAction(CopyAction delegate) {
this.delegate = delegate;
}
@Override
public WorkResult execute(CopyActionProcessingStream stream) {
return this.delegate.execute((action) -> {
Map<RelativePath, FileCopyDetailsInternal> detailsByPath = new TreeMap<>();
stream.process((details) -> detailsByPath.put(details.getRelativePath(), details));
detailsByPath.values().forEach(action::processFile);
});
}
}
}

View File

@ -38,8 +38,6 @@ import org.gradle.api.tasks.bundling.Jar;
import org.gradle.work.DisableCachingByDefault;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.loader.tools.LoaderImplementation;
/**
* A custom {@link Jar} task that produces a Spring Boot executable jar.
*
@ -145,13 +143,12 @@ public abstract class BootJar extends Jar implements BootArchive {
@Override
protected CopyAction createCopyAction() {
LoaderImplementation loaderImplementation = getLoaderImplementation().getOrElse(LoaderImplementation.DEFAULT);
LayerResolver layerResolver = null;
if (!isLayeredDisabled()) {
layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);
}
String jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null;
return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, true, layerResolver,
return this.support.createCopyAction(this, this.resolvedDependencies, true, layerResolver,
jarmodeToolsLocation);
}

View File

@ -38,8 +38,6 @@ import org.gradle.api.tasks.bundling.War;
import org.gradle.work.DisableCachingByDefault;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.loader.tools.LoaderImplementation;
/**
* A custom {@link War} task that produces a Spring Boot executable war.
*
@ -119,14 +117,13 @@ public abstract class BootWar extends War implements BootArchive {
@Override
protected CopyAction createCopyAction() {
LoaderImplementation loaderImplementation = getLoaderImplementation().getOrElse(LoaderImplementation.DEFAULT);
LayerResolver layerResolver = null;
if (!isLayeredDisabled()) {
layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);
}
String jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null;
return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, false,
layerResolver, jarmodeToolsLocation);
return this.support.createCopyAction(this, this.resolvedDependencies, false, layerResolver,
jarmodeToolsLocation);
}
private boolean isIncludeJarmodeTools() {

View File

@ -23,13 +23,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.HashMap;
import java.util.HexFormat;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -63,7 +60,6 @@ import org.springframework.boot.loader.tools.JarModeLibrary;
import org.springframework.boot.loader.tools.Layer;
import org.springframework.boot.loader.tools.LayersIndex;
import org.springframework.boot.loader.tools.LibraryCoordinates;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.boot.loader.tools.NativeImageArgFile;
import org.springframework.boot.loader.tools.ReachabilityMetadataProperties;
import org.springframework.util.Assert;
@ -120,15 +116,13 @@ class BootZipCopyAction implements CopyAction {
private final @Nullable LayerResolver layerResolver;
private final LoaderImplementation loaderImplementation;
BootZipCopyAction(File output, Manifest manifest, boolean preserveFileTimestamps, @Nullable Integer dirMode,
@Nullable Integer fileMode, boolean includeDefaultLoader, @Nullable String jarmodeToolsLocation,
Spec<FileTreeElement> requiresUnpack, Spec<FileTreeElement> exclusions,
@Nullable LaunchScriptConfiguration launchScript, Spec<FileCopyDetails> librarySpec,
Function<FileCopyDetails, ZipCompression> compressionResolver, @Nullable String encoding,
ResolvedDependencies resolvedDependencies, boolean supportsSignatureFile,
@Nullable LayerResolver layerResolver, LoaderImplementation loaderImplementation) {
@Nullable LayerResolver layerResolver) {
this.output = output;
this.manifest = manifest;
this.preserveFileTimestamps = preserveFileTimestamps;
@ -145,7 +139,6 @@ class BootZipCopyAction implements CopyAction {
this.resolvedDependencies = resolvedDependencies;
this.supportsSignatureFile = supportsSignatureFile;
this.layerResolver = layerResolver;
this.loaderImplementation = loaderImplementation;
}
@Override
@ -329,8 +322,7 @@ class BootZipCopyAction implements CopyAction {
// Always write loader entries after META-INF directory (see gh-16698)
return;
}
LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime(), getDirMode(), getFileMode(),
BootZipCopyAction.this.loaderImplementation);
LoaderZipEntries loaderEntries = new LoaderZipEntries(getTime(), getDirMode(), getFileMode());
this.writtenLoaderEntries = loaderEntries.writeTo(this.out);
if (BootZipCopyAction.this.layerResolver != null) {
for (String name : this.writtenLoaderEntries.getFiles()) {
@ -512,9 +504,13 @@ class BootZipCopyAction implements CopyAction {
? details.getPermissions().toUnixNumeric() : getMode(details);
}
@SuppressWarnings("deprecation")
private int getMode(FileCopyDetails details) {
return details.getMode();
try {
return (int) details.getClass().getMethod("getMode").invoke(details);
}
catch (Exception ex) {
throw new RuntimeException("Failed to get mode from FileCopyDetails", ex);
}
}
}
@ -590,36 +586,24 @@ class BootZipCopyAction implements CopyAction {
private static final int BUFFER_SIZE = 32 * 1024;
private final @Nullable MessageDigest messageDigest;
private final boolean unpack;
private final CRC32 crc = new CRC32();
private long size;
StoredEntryPreparator(InputStream inputStream, boolean unpack) throws IOException {
this.messageDigest = (unpack) ? sha1Digest() : null;
this.unpack = unpack;
try (inputStream) {
load(inputStream);
}
}
private static MessageDigest sha1Digest() {
try {
return MessageDigest.getInstance("SHA-1");
}
catch (NoSuchAlgorithmException ex) {
throw new IllegalStateException(ex);
}
}
private void load(InputStream inputStream) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
this.crc.update(buffer, 0, bytesRead);
if (this.messageDigest != null) {
this.messageDigest.update(buffer, 0, bytesRead);
}
this.size += bytesRead;
}
}
@ -629,8 +613,8 @@ class BootZipCopyAction implements CopyAction {
entry.setCompressedSize(this.size);
entry.setCrc(this.crc.getValue());
entry.setMethod(ZipEntry.STORED);
if (this.messageDigest != null) {
entry.setComment("UNPACK:" + HexFormat.of().formatHex(this.messageDigest.digest()));
if (this.unpack) {
entry.setComment("UNPACK");
}
}

View File

@ -29,7 +29,6 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.gradle.api.file.FileTreeElement;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
@ -42,27 +41,22 @@ import org.springframework.util.StreamUtils;
*/
class LoaderZipEntries {
private final LoaderImplementation loaderImplementation;
private final @Nullable Long entryTime;
private final int dirMode;
private final int fileMode;
LoaderZipEntries(@Nullable Long entryTime, int dirMode, int fileMode,
@Nullable LoaderImplementation loaderImplementation) {
LoaderZipEntries(@Nullable Long entryTime, int dirMode, int fileMode) {
this.entryTime = entryTime;
this.dirMode = dirMode;
this.fileMode = fileMode;
this.loaderImplementation = (loaderImplementation != null) ? loaderImplementation
: LoaderImplementation.DEFAULT;
}
WrittenEntries writeTo(ZipArchiveOutputStream out) throws IOException {
WrittenEntries written = new WrittenEntries();
try (ZipInputStream loaderJar = new ZipInputStream(
getResourceAsStream("/" + this.loaderImplementation.getJarResourceName()))) {
getResourceAsStream("/META-INF/loader/spring-boot-loader.jar"))) {
java.util.zip.ZipEntry entry = loaderJar.getNextEntry();
while (entry != null) {
if (entry.isDirectory() && !entry.getName().equals("META-INF/")) {

View File

@ -124,7 +124,7 @@ class PackagingDocumentationTests {
try (JarFile jar = new JarFile(file)) {
JarEntry entry = jar.getJarEntry("BOOT-INF/lib/jruby-complete-1.7.25.jar");
assertThat(entry).isNotNull();
assertThat(entry.getComment()).startsWith("UNPACK:");
assertThat(entry.getComment()).isEqualTo("UNPACK");
}
}

View File

@ -24,8 +24,6 @@ import java.time.format.DateTimeFormatter;
import java.util.Properties;
import org.gradle.api.Project;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.initialization.GradlePropertiesController;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@ -173,11 +171,7 @@ class BuildInfoTests {
private Project createProject(String projectName) {
File projectDir = new File(this.temp, projectName);
Project project = GradleProjectBuilder.builder().withProjectDir(projectDir).withName(projectName).build();
((ProjectInternal) project).getServices()
.get(GradlePropertiesController.class)
.loadGradlePropertiesFrom(projectDir, false);
return project;
return GradleProjectBuilder.builder().withProjectDir(projectDir).withName(projectName).build();
}
private BuildInfo createTask(Project project) {

View File

@ -108,16 +108,6 @@ abstract class AbstractBootArchiveIntegrationTests {
assertThat(firstHash).isEqualTo(secondHash);
}
@TestTemplate
void classicLoader() throws IOException {
assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName).getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
File jar = new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0];
try (JarFile jarFile = new JarFile(jar)) {
assertThat(jarFile.getEntry("org/springframework/boot/loader/LaunchedURLClassLoader.class")).isNotNull();
}
}
@TestTemplate
void upToDateWhenBuiltTwice() {
assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName).getOutcome())
@ -243,15 +233,9 @@ abstract class AbstractBootArchiveIntegrationTests {
.filter((entry) -> !entry.isDirectory())
.map(JarEntry::getName)
.filter((name) -> name.startsWith(this.libPath));
if (this.gradleBuild.gradleVersionIsLessThan("9.0.0-rc-1")) {
assertThat(libEntryNames).containsExactly(this.libPath + "two-1.0.jar",
this.libPath + "commons-io-2.19.0.jar");
}
else {
assertThat(libEntryNames).containsExactly(this.libPath + "commons-io-2.19.0.jar",
this.libPath + "two-1.0.jar");
}
}
}
@TestTemplate
@ -293,6 +277,7 @@ abstract class AbstractBootArchiveIntegrationTests {
void jarTypeFilteringIsApplied() throws IOException {
File flatDirRepository = new File(this.gradleBuild.getProjectDir(), "repository");
createDependenciesStarterJar(new File(flatDirRepository, "starter.jar"));
createDependenciesDeveloperToolsJar(new File(flatDirRepository, "devonly.jar"));
createStandardJar(new File(flatDirRepository, "standard.jar"));
assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName).getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
@ -669,6 +654,10 @@ abstract class AbstractBootArchiveIntegrationTests {
createJar(location, (attributes) -> attributes.putValue("Spring-Boot-Jar-Type", "dependencies-starter"));
}
private void createDependenciesDeveloperToolsJar(File location) throws IOException {
createJar(location, (attributes) -> attributes.putValue("Spring-Boot-Jar-Type", "development-tool"));
}
private void createJar(File location, Consumer<Attributes> attributesConfigurer) throws IOException {
location.getParentFile().mkdirs();
Manifest manifest = new Manifest();

View File

@ -27,6 +27,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.PosixFilePermission;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
@ -35,6 +37,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
@ -65,7 +68,6 @@ import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.gradle.junit.GradleProjectBuilder;
import org.springframework.boot.loader.tools.DefaultLaunchScript;
import org.springframework.boot.loader.tools.JarModeLibrary;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -283,17 +285,6 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
}
}
@Test
void loaderIsWrittenToTheRootOfTheJarWhenUsingClassicLoader() throws IOException {
this.task.getMainClass().set("com.example.Main");
this.task.getLoaderImplementation().set(LoaderImplementation.CLASSIC);
executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry("org/springframework/boot/loader/LaunchedURLClassLoader.class")).isNotNull();
assertThat(jarFile.getEntry("org/springframework/boot/loader/")).isNotNull();
}
}
@Test
void unpackCommentIsAddedToEntryIdentifiedByAPattern() throws IOException {
this.task.getMainClass().set("com.example.Main");
@ -301,7 +292,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
this.task.requiresUnpack("**/one.jar");
executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry(this.libPath + "one.jar").getComment()).startsWith("UNPACK:");
assertThat(jarFile.getEntry(this.libPath + "one.jar").getComment()).isEqualTo("UNPACK");
assertThat(jarFile.getEntry(this.libPath + "two.jar").getComment()).isNull();
}
}
@ -313,7 +304,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
this.task.requiresUnpack((element) -> element.getName().endsWith("two.jar"));
executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getEntry(this.libPath + "two.jar").getComment()).startsWith("UNPACK:");
assertThat(jarFile.getEntry(this.libPath + "two.jar").getComment()).isEqualTo("UNPACK");
assertThat(jarFile.getEntry(this.libPath + "one.jar").getComment()).isNull();
}
}
@ -419,23 +410,46 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
}
@Test
void reproducibleOrderingCanBeEnabled() throws IOException {
void archiveIsReproducibleByDefault() throws IOException {
this.task.getMainClass().set("com.example.Main");
this.task.from(newFile("bravo.txt"), newFile("alpha.txt"), newFile("charlie.txt"));
this.task.setReproducibleFileOrder(true);
this.task.from(newFiles("files/b/bravo.txt", "files/a/alpha.txt", "files/c/charlie.txt"));
executeTask();
assertThat(this.task.getArchiveFile().get().getAsFile()).exists();
List<String> textFiles = new ArrayList<>();
List<String> files = new ArrayList<>();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".txt")) {
textFiles.add(entry.getName());
assertThat(entry.getLastModifiedTime().toMillis())
.isEqualTo(ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES);
if (entry.getName().startsWith("files/")) {
files.add(entry.getName());
}
}
}
assertThat(files).containsExactly("files/", "files/a/", "files/a/alpha.txt", "files/b/", "files/b/bravo.txt",
"files/c/", "files/c/charlie.txt");
}
@Test
void archiveReproducibilityCanBeDisabled() throws IOException {
this.task.getMainClass().set("com.example.Main");
this.task.from(newFiles("files/b/bravo.txt", "files/a/alpha.txt", "files/c/charlie.txt"));
this.task.setPreserveFileTimestamps(true);
this.task.setReproducibleFileOrder(false);
executeTask();
assertThat(this.task.getArchiveFile().get().getAsFile()).exists();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".txt") || entry.getName().startsWith("BOOT-INF/lib/")) {
OffsetDateTime lastModifiedTime = entry.getLastModifiedTime().toInstant().atOffset(ZoneOffset.UTC);
assertThat(lastModifiedTime)
.isNotEqualTo(OffsetDateTime.of(1980, 2, 1, 0, 0, 0, 0, ZoneOffset.UTC));
}
}
}
assertThat(textFiles).containsExactly("alpha.txt", "bravo.txt", "charlie.txt");
}
@Test
@ -675,6 +689,19 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
return entryNames;
}
protected File newFiles(String... names) throws IOException {
File dir = new File(this.temp, UUID.randomUUID().toString());
dir.mkdir();
List<File> files = new ArrayList<>();
for (String name : names) {
File file = new File(dir, name);
file.getParentFile().mkdirs();
file.createNewFile();
files.add(file);
}
return dir;
}
protected File newFile(String name) throws IOException {
File file = new File(this.temp, name);
file.createNewFile();

View File

@ -30,8 +30,8 @@ import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.buildpack.platform.build.BuildRequest;
import org.springframework.boot.buildpack.platform.build.BuildpackReference;
import org.springframework.boot.buildpack.platform.build.PullPolicy;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.gradle.junit.GradleProjectBuilder;

View File

@ -66,18 +66,10 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
copyClasspathApplication();
BuildResult result = this.gradleBuild.build("launch");
String output = result.getOutput();
if (this.gradleBuild.gradleVersionIsLessThan("9.0.0-rc-1")) {
assertThat(output).containsPattern("1\\. .*classes");
assertThat(output).containsPattern("2\\. .*library-1.0-SNAPSHOT.jar");
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
assertThat(output).containsPattern("4\\. .*spring-boot-jarmode-tools.*.jar");
}
else {
assertThat(output).containsPattern("1\\. .*classes");
assertThat(output).containsPattern("2\\. .*commons-lang3-3.9.jar");
assertThat(output).containsPattern("3\\. .*library-1.0-SNAPSHOT.jar");
assertThat(output).containsPattern("4\\. .*spring-boot-jarmode-tools.*.jar");
}
assertThat(output).doesNotContain("5. ");
}
@ -86,18 +78,10 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
copyClasspathApplication();
BuildResult result = this.gradleBuild.build("launch");
String output = result.getOutput();
if (this.gradleBuild.gradleVersionIsLessThan("9.0.0-rc-1")) {
assertThat(output).containsPattern("1\\. .*classes");
assertThat(output).containsPattern("2\\. .*spring-boot-jarmode-tools.*.jar");
assertThat(output).containsPattern("3\\. .*library-1.0-SNAPSHOT.jar");
assertThat(output).containsPattern("4\\. .*commons-lang3-3.9.jar");
}
else {
assertThat(output).containsPattern("1\\. .*classes");
assertThat(output).containsPattern("2\\. .*spring-boot-jarmode-tools.*.jar");
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
assertThat(output).containsPattern("4\\. .*library-1.0-SNAPSHOT.jar");
}
assertThat(output).doesNotContain("5. ");
}

View File

@ -21,6 +21,8 @@ plugins {
bootJar {
mainClass = 'com.example.Application'
if (GradleVersion.current().compareTo(GradleVersion.version("9.0.0-rc-1")) < 0) {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
}

View File

@ -21,6 +21,8 @@ plugins {
bootWar {
mainClass = 'com.example.Application'
if (GradleVersion.current().compareTo(GradleVersion.version("9.0.0-rc-1")) < 0) {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
}

View File

@ -6,7 +6,7 @@
<!-- tag::different-versions[] -->
<properties>
<slf4j.version>1.7.30</slf4j.version>
<spring-data-releasetrain.version>Moore-SR6</spring-data-releasetrain.version>
<spring-data-bom.version>2024.1.10</spring-data-bom.version>
</properties>
<!-- end::different-versions[] -->

View File

@ -24,8 +24,8 @@
<!-- Override Spring Data release train provided by Spring Boot -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>2020.0.0-SR1</version>
<artifactId>spring-data-bom</artifactId>
<version>2024.1.10</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -67,6 +67,9 @@ include::example$using/different-versions-pom.xml[tags=different-versions]
Browse the xref:appendix:dependency-versions/properties.adoc[Dependency Versions Properties] section in the Spring Boot reference for a complete list of dependency version properties.
WARNING: Each Spring Boot release is designed and tested against a specific set of third-party dependencies.
Overriding versions may cause compatibility issues and should be done with care.
[[using.import]]

View File

@ -159,7 +159,7 @@ abstract class AbstractArchiveIntegrationTests {
Optional<JarEntry> match = entries.filter((entry) -> entry.getName().startsWith(prefix))
.findFirst();
assertThat(match).as("Name starting with %s", prefix)
.hasValueSatisfying((entry) -> assertThat(entry.getComment()).startsWith("UNPACK:"));
.hasValueSatisfying((entry) -> assertThat(entry.getComment()).isEqualTo("UNPACK"));
});
});
return this;

View File

@ -76,26 +76,6 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
});
}
@TestTemplate
void whenJarWithClassicLoaderIsRepackagedInPlaceOnlyRepackagedJarIsInstalled(MavenBuild mavenBuild) {
mavenBuild.project("jar-with-classic-loader").goals("install").execute((project) -> {
File original = new File(project, "target/jar-with-classic-loader-0.0.1.BUILD-SNAPSHOT.jar.original");
assertThat(original).isFile();
File repackaged = new File(project, "target/jar-with-classic-loader-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(launchScript(repackaged)).isEmpty();
assertThat(jar(repackaged)).manifest((manifest) -> {
manifest.hasMainClass("org.springframework.boot.loader.launch.JarLauncher");
manifest.hasStartClass("some.random.Main");
manifest.hasAttribute("Not-Used", "Foo");
}).hasEntryWithName("org/springframework/boot/loader/launch/JarLauncher.class");
assertThat(buildLog(project))
.contains("Replacing main artifact " + repackaged + " with repackaged archive,")
.contains("The original artifact has been renamed to " + original)
.contains("Installing " + repackaged + " to")
.doesNotContain("Installing " + original + " to");
});
}
@TestTemplate
void whenAttachIsDisabledOnlyTheOriginalJarIsInstalled(MavenBuild mavenBuild) {
mavenBuild.project("jar-attach-disabled").goals("install").execute((project) -> {
@ -196,7 +176,40 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core")
.hasEntryWithNameStartingWith("BOOT-INF/lib/commons-logging")
.doesNotHaveEntryWithName("BOOT-INF/lib/servlet-api-2.5.jar");
.doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/servlet-api-");
});
}
@TestTemplate
void whenAnEntryIsOptionalByDefaultDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {
mavenBuild.project("jar-optional-default").goals("install").execute((project) -> {
File repackaged = new File(project, "target/jar-optional-default-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core")
.doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/log4j-api-");
});
}
@TestTemplate
void whenAnEntryIsOptionalAndOptionalsIncludedAppearsInTheRepackagedJar(MavenBuild mavenBuild) {
mavenBuild.project("jar-optional-include").goals("install").execute((project) -> {
File repackaged = new File(project, "target/jar-optional-include-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core")
.hasEntryWithNameStartingWith("BOOT-INF/lib/log4j-api-");
});
}
@TestTemplate
void whenAnEntryIsOptionalAndOptionalsExcludedDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {
mavenBuild.project("jar-optional-exclude").goals("install").execute((project) -> {
File repackaged = new File(project, "target/jar-optional-exclude-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core")
.doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/log4j-api-");
});
}
@ -248,9 +261,8 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
File repackaged = new File(project, "target/jar-exclude-group-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context")
.hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core")
.hasEntryWithNameStartingWith("BOOT-INF/lib/commons-logging")
.doesNotHaveEntryWithName("BOOT-INF/lib/log4j-api-2.4.1.jar");
.doesNotHaveEntryWithName("BOOT-INF/lib/log4j-api-");
});
}
@ -388,7 +400,7 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
assertThat(layerIndex.get("application")).contains("BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar",
"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(layerIndex.get("dependencies"))
.anyMatch((dependency) -> dependency.startsWith("BOOT-INF/lib/log4j-api-2"));
.anyMatch((dependency) -> dependency.startsWith("BOOT-INF/lib/log4j-api-"));
}
catch (IOException ex) {
// Ignore

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-optional-default</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>@java.version@</maven.compiler.source>
<maven.compiler.target>@java.version@</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>@maven-jar-plugin.version@</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>@spring-framework.version@</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>@log4j2.version@</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-with-classic-loader</artifactId>
<artifactId>jar-optional-exclude</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -22,7 +22,7 @@
<goal>repackage</goal>
</goals>
<configuration>
<loaderImplementation>CLASSIC</loaderImplementation>
<includeOptional>false</includeOptional>
</configuration>
</execution>
</executions>
@ -31,16 +31,6 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>@maven-jar-plugin.version@</version>
<configuration>
<archive>
<manifest>
<mainClass>some.random.Main</mainClass>
</manifest>
<manifestEntries>
<Not-Used>Foo</Not-Used>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
@ -51,10 +41,10 @@
<version>@spring-framework.version@</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>@jakarta-servlet.version@</version>
<scope>provided</scope>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>@log4j2.version@</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -14,7 +14,11 @@
* limitations under the License.
*/
/**
* Utilities used by Spring Boot's JAR loading.
*/
package org.springframework.boot.loader.util;
package org.test;
public class SampleApplication {
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-optional-include</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>@java.version@</maven.compiler.source>
<maven.compiler.target>@java.version@</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<includeOptional>true</includeOptional>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>@maven-jar-plugin.version@</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>@spring-framework.version@</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>@log4j2.version@</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -14,7 +14,11 @@
* limitations under the License.
*/
/**
* Support for loading and manipulating JAR/WAR files.
*/
package org.springframework.boot.loader.jar;
package org.test;
public class SampleApplication {
public static void main(String[] args) {
}
}

View File

@ -47,7 +47,6 @@ import org.springframework.boot.loader.tools.Layouts.Jar;
import org.springframework.boot.loader.tools.Layouts.None;
import org.springframework.boot.loader.tools.Layouts.War;
import org.springframework.boot.loader.tools.Libraries;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.boot.loader.tools.Packager;
import org.springframework.boot.loader.tools.layer.CustomLayers;
@ -114,6 +113,13 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
@Parameter(defaultValue = "false")
public boolean includeSystemScope;
/**
* Include optional dependencies.
* @since 3.5.7
*/
@Parameter(defaultValue = "false")
public boolean includeOptional;
/**
* Include JAR tools.
* @since 3.3.0
@ -142,15 +148,6 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
return null;
}
/**
* Return the loader implementation that should be used.
* @return the loader implementation or {@code null}
* @since 3.2.0
*/
protected @Nullable LoaderImplementation getLoaderImplementation() {
return null;
}
/**
* Return the layout factory that will be used to determine the {@link LayoutType} if
* no explicit layout is set.
@ -168,7 +165,6 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
*/
protected <P extends Packager> P getConfiguredPackager(Supplier<P> supplier) {
P packager = supplier.get();
packager.setLoaderImplementation(getLoaderImplementation());
packager.setLayoutFactory(getLayoutFactory());
packager.addMainClassTimeoutWarningListener(new LoggingMainClassTimeoutWarningListener(this::getLog));
packager.setMainClass(this.mainClass);
@ -231,6 +227,9 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
if (!this.includeSystemScope) {
filters.add(new ScopeFilter(null, Artifact.SCOPE_SYSTEM));
}
if (!this.includeOptional) {
filters.add(DependencyFilter.exclude(Artifact::isOptional));
}
return filters.toArray(new ArtifactsFilter[0]);
}

View File

@ -50,7 +50,6 @@ import org.springframework.boot.loader.tools.EntryWriter;
import org.springframework.boot.loader.tools.ImagePackager;
import org.springframework.boot.loader.tools.LayoutFactory;
import org.springframework.boot.loader.tools.Libraries;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -208,13 +207,6 @@ public abstract class BuildImageMojo extends AbstractPackagerMojo {
@Parameter
private @Nullable LayoutType layout;
/**
* The loader implementation that should be used.
* @since 3.2.0
*/
@Parameter
private @Nullable LoaderImplementation loaderImplementation;
/**
* The layout factory that will be used to create the executable archive if no
* explicit layout is set. Alternative layouts implementations can be provided by 3rd
@ -238,11 +230,6 @@ public abstract class BuildImageMojo extends AbstractPackagerMojo {
return this.layout;
}
@Override
protected @Nullable LoaderImplementation getLoaderImplementation() {
return this.loaderImplementation;
}
/**
* Return the layout factory that will be used to determine the
* {@link AbstractPackagerMojo.LayoutType} if no explicit layout is set.

View File

@ -16,9 +16,11 @@
package org.springframework.boot.maven;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter;
@ -81,4 +83,22 @@ public abstract class DependencyFilter extends AbstractArtifactsFilter {
return this.filters;
}
/**
* Return a new {@link DependencyFilter} the excludes artifacts based on the given
* predicate.
* @param filter the predicate used to filter the artifacts.
* @return a new {@link DependencyFilter} instance
* @since 3.5.7
*/
public static DependencyFilter exclude(Predicate<Artifact> filter) {
return new DependencyFilter(Collections.emptyList()) {
@Override
protected boolean filter(Artifact artifact) {
return filter.test(artifact);
}
};
}
}

View File

@ -34,8 +34,8 @@ import org.apache.maven.artifact.Artifact;
*/
class JarTypeFilter extends DependencyFilter {
private static final Set<String> EXCLUDED_JAR_TYPES = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList("annotation-processor", "dependencies-starter")));
private static final Set<String> EXCLUDED_JAR_TYPES = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList("annotation-processor", "dependencies-starter", "development-tool")));
JarTypeFilter() {
super(Collections.emptyList());

View File

@ -40,7 +40,6 @@ import org.springframework.boot.loader.tools.DefaultLaunchScript;
import org.springframework.boot.loader.tools.LaunchScript;
import org.springframework.boot.loader.tools.LayoutFactory;
import org.springframework.boot.loader.tools.Libraries;
import org.springframework.boot.loader.tools.LoaderImplementation;
import org.springframework.boot.loader.tools.Repackager;
import org.springframework.lang.Contract;
import org.springframework.util.StringUtils;
@ -170,13 +169,6 @@ public class RepackageMojo extends AbstractPackagerMojo {
@Parameter(property = "spring-boot.repackage.layout")
private @Nullable LayoutType layout;
/**
* The loader implementation that should be used.
* @since 3.2.0
*/
@Parameter
private @Nullable LoaderImplementation loaderImplementation;
/**
* The layout factory that will be used to create the executable archive if no
* explicit layout is set. Alternative layouts implementations can be provided by 3rd
@ -201,11 +193,6 @@ public class RepackageMojo extends AbstractPackagerMojo {
return this.layout;
}
@Override
protected @Nullable LoaderImplementation getLoaderImplementation() {
return this.loaderImplementation;
}
/**
* Return the layout factory that will be used to determine the
* {@link AbstractPackagerMojo.LayoutType} if no explicit layout is set.

View File

@ -0,0 +1,50 @@
/*
* 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.maven;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DependencyFilter}.
*
* @author Phillip Webb
*/
class DependencyFilterTests {
@Test
void excludeFiltersBasedOnPredicate() throws ArtifactFilterException {
DependencyFilter filter = DependencyFilter.exclude(Artifact::isOptional);
ArtifactHandler ah = new DefaultArtifactHandler();
VersionRange v = VersionRange.createFromVersion("1.0.0");
DefaultArtifact a1 = new DefaultArtifact("com.example", "a1", v, "compile", "jar", null, ah, false);
DefaultArtifact a2 = new DefaultArtifact("com.example", "a2", v, "compile", "jar", null, ah, true);
DefaultArtifact a3 = new DefaultArtifact("com.example", "a3", v, "compile", "jar", null, ah, false);
Set<Artifact> filtered = filter.filter(Set.of(a1, a2, a3));
assertThat(filtered).containsExactlyInAnyOrder(a1, a3);
}
}

View File

@ -31,8 +31,8 @@ import org.springframework.boot.buildpack.platform.build.BuildRequest;
import org.springframework.boot.buildpack.platform.build.BuildpackReference;
import org.springframework.boot.buildpack.platform.build.Cache;
import org.springframework.boot.buildpack.platform.build.PullPolicy;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.Owner;
import org.springframework.boot.buildpack.platform.io.TarArchive;

View File

@ -60,6 +60,11 @@ class JarTypeFilterTests {
assertThat(new JarTypeFilter().filter(createArtifact("annotation-processor"))).isTrue();
}
@Test
void whenArtifactHasDevelopmentToolJarTypeThenItIsExcluded() {
assertThat(new JarTypeFilter().filter(createArtifact("development-tool"))).isTrue();
}
@Test
void whenArtifactHasNoManifestFileThenItIsIncluded() {
assertThat(new JarTypeFilter().filter(createArtifactWithNoManifest())).isFalse();

View File

@ -52,7 +52,7 @@ dependencies {
implementation("commons-codec:commons-codec:${commonsCodecVersion}")
implementation("de.undercouch.download:de.undercouch.download.gradle.plugin:5.5.0")
implementation("dev.adamko.dokkatoo:dokkatoo-plugin:2.3.1")
implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.8")
implementation("dev.detekt:detekt-gradle-plugin:2.0.0-alpha.0")
implementation("io.spring.gradle.antora:spring-antora-plugin:0.0.1")
implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}")
implementation("io.spring.nohttp:nohttp-gradle:0.0.11")
@ -133,10 +133,6 @@ gradlePlugin {
id = "org.springframework.boot.integration-test"
implementationClass = "org.springframework.boot.build.test.IntegrationTestPlugin"
}
systemTestPlugin {
id = "org.springframework.boot.system-test"
implementationClass = "org.springframework.boot.build.test.SystemTestPlugin"
}
mavenPluginPlugin {
id = "org.springframework.boot.maven-plugin"
implementationClass = "org.springframework.boot.build.mavenplugin.MavenPluginPlugin"
@ -153,10 +149,22 @@ gradlePlugin {
id = "org.springframework.boot.starter"
implementationClass = "org.springframework.boot.build.starters.StarterPlugin"
}
systemTestPlugin {
id = "org.springframework.boot.system-test"
implementationClass = "org.springframework.boot.build.test.SystemTestPlugin"
}
testAutoConfigurationPlugin {
id = "org.springframework.boot.test-auto-configuration"
implementationClass = "org.springframework.boot.build.test.autoconfigure.TestAutoConfigurationPlugin"
}
testFailuresPlugin {
id = "org.springframework.boot.test-failures"
implementationClass = "org.springframework.boot.build.testing.TestFailuresPlugin"
}
testSlicePlugin {
id = "org.springframework.boot.test-slice"
implementationClass = "org.springframework.boot.build.test.autoconfigure.TestSlicePlugin"
}
}
}

View File

@ -20,9 +20,9 @@ import java.net.URI;
import dev.adamko.dokkatoo.DokkatooExtension;
import dev.adamko.dokkatoo.formats.DokkatooHtmlPlugin;
import io.gitlab.arturbosch.detekt.Detekt;
import io.gitlab.arturbosch.detekt.DetektPlugin;
import io.gitlab.arturbosch.detekt.extensions.DetektExtension;
import dev.detekt.gradle.Detekt;
import dev.detekt.gradle.extensions.DetektExtension;
import dev.detekt.gradle.plugin.DetektPlugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
@ -76,6 +76,7 @@ class KotlinConventions {
private void configureDokkatoo(Project project) {
DokkatooExtension dokkatoo = project.getExtensions().getByType(DokkatooExtension.class);
dokkatoo.getVersions().getJetbrainsDokka().set("2.1.0-Beta");
dokkatoo.getDokkatooSourceSets().configureEach((sourceSet) -> {
if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) {
sourceSet.getSourceRoots().setFrom(project.file("src/main/kotlin"));
@ -103,7 +104,9 @@ class KotlinConventions {
project.getPlugins().apply(DetektPlugin.class);
DetektExtension detekt = project.getExtensions().getByType(DetektExtension.class);
detekt.getConfig().setFrom(project.getRootProject().file("config/detekt/config.yml"));
project.getTasks().withType(Detekt.class).configureEach((task) -> task.setJvmTarget(JVM_TARGET.getTarget()));
project.getTasks()
.withType(Detekt.class)
.configureEach((task) -> task.getJvmTarget().set(JVM_TARGET.getTarget()));
}
}

View File

@ -80,6 +80,13 @@ final class ArchitectureRules {
private static final String AUTOCONFIGURATION_ANNOTATION = "org.springframework.boot.autoconfigure.AutoConfiguration";
private static final String TEST_AUTOCONFIGURATION_ANNOTATION = "org.springframework.boot.test.autoconfigure.TestAutoConfiguration";
private static final Predicate<JavaPackage> NULL_MARKED_PACKAGE_FILTER = (candidate) -> !List
.of("org.springframework.boot.cli.json", "org.springframework.boot.configurationmetadata.json",
"org.springframework.boot.configurationprocessor.json")
.contains(candidate.getName());
private ArchitectureRules() {
}
@ -112,6 +119,7 @@ final class ArchitectureRules {
rules.add(allConfigurationPropertiesBindingBeanMethodsShouldBeStatic());
rules.add(autoConfigurationClassesShouldBePublicAndFinal());
rules.add(autoConfigurationClassesShouldHaveNoPublicMembers());
rules.add(testAutoConfigurationClassesShouldBePackagePrivateAndFinal());
return List.copyOf(rules);
}
@ -130,7 +138,12 @@ final class ArchitectureRules {
}
private static ArchRule allPackagesShouldBeFreeOfTangles() {
return SlicesRuleDefinition.slices().matching("(**)").should().beFreeOfCycles();
return SlicesRuleDefinition.slices()
.matching("(**)")
.should()
.beFreeOfCycles()
.ignoreDependency("org.springframework.boot.env.EnvironmentPostProcessor",
"org.springframework.boot.SpringApplication");
}
private static ArchRule allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization() {
@ -250,7 +263,9 @@ final class ArchitectureRules {
}
static ArchRule packagesShouldBeAnnotatedWithNullMarked() {
return ArchRuleDefinition.all(packages()).should(beAnnotatedWithNullMarked()).allowEmptyShould(true);
return ArchRuleDefinition.all(packages(NULL_MARKED_PACKAGE_FILTER))
.should(beAnnotatedWithNullMarked())
.allowEmptyShould(true);
}
private static ArchCondition<? super JavaMethod> notSpecifyOnlyATypeThatIsTheSameAsTheMethodReturnType() {
@ -353,8 +368,7 @@ final class ArchitectureRules {
private static ArchRule autoConfigurationClassesShouldBePublicAndFinal() {
return ArchRuleDefinition.classes()
.that()
.areAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)
.that(areRegularAutoConfiguration())
.should()
.bePublic()
.andShould()
@ -365,8 +379,7 @@ final class ArchitectureRules {
private static ArchRule autoConfigurationClassesShouldHaveNoPublicMembers() {
return ArchRuleDefinition.members()
.that()
.areDeclaredInClassesThat()
.areAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)
.areDeclaredInClassesThat(areRegularAutoConfiguration())
.and(areNotDefaultConstructors())
.and(areNotConstants())
.and(dontOverridePublicMethods())
@ -375,6 +388,24 @@ final class ArchitectureRules {
.allowEmptyShould(true);
}
private static ArchRule testAutoConfigurationClassesShouldBePackagePrivateAndFinal() {
return ArchRuleDefinition.classes()
.that()
.areAnnotatedWith(TEST_AUTOCONFIGURATION_ANNOTATION)
.should()
.bePackagePrivate()
.andShould()
.haveModifier(JavaModifier.FINAL)
.allowEmptyShould(true);
}
private static DescribedPredicate<JavaClass> areRegularAutoConfiguration() {
return DescribedPredicate.describe("Regular @AutoConfiguration",
(javaClass) -> javaClass.isMetaAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)
&& !javaClass.isMetaAnnotatedWith(TEST_AUTOCONFIGURATION_ANNOTATION)
&& !javaClass.isAnnotation());
}
private static DescribedPredicate<? super JavaMember> dontOverridePublicMethods() {
OverridesPublicMethod<JavaMember> predicate = new OverridesPublicMethod<>();
return DescribedPredicate.describe("don't override public methods", (member) -> !predicate.test(member));
@ -480,11 +511,11 @@ final class ArchitectureRules {
return string + " should be used instead";
}
static ClassesTransformer<JavaPackage> packages() {
static ClassesTransformer<JavaPackage> packages(Predicate<JavaPackage> filter) {
return new AbstractClassesTransformer<>("packages") {
@Override
public Iterable<JavaPackage> doTransform(JavaClasses collection) {
return collection.stream().map(JavaClass::getPackage).collect(Collectors.toSet());
return collection.stream().map(JavaClass::getPackage).filter(filter).collect(Collectors.toSet());
}
};
}

View File

@ -19,6 +19,7 @@ package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
@ -54,8 +55,8 @@ public record AutoConfigurationClass(String name, List<String> before, List<Stri
attributes.getOrDefault("afterName", Collections.emptyList()));
}
static AutoConfigurationClass of(File classFile) {
try (FileInputStream input = new FileInputStream(classFile)) {
public static AutoConfigurationClass of(InputStream input) {
try {
ClassReader classReader = new ClassReader(input);
AutoConfigurationClassVisitor visitor = new AutoConfigurationClassVisitor();
classReader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
@ -66,6 +67,15 @@ public record AutoConfigurationClass(String name, List<String> before, List<Stri
}
}
static AutoConfigurationClass of(File classFile) {
try (InputStream input = new FileInputStream(classFile)) {
return of(input);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private static final class AutoConfigurationClassVisitor extends ClassVisitor {
private AutoConfigurationClass autoConfigurationClass;

View File

@ -38,7 +38,10 @@ import org.gradle.api.tasks.SkipWhenEmpty;
*/
public abstract class AutoConfigurationImportsTask extends DefaultTask {
static final String IMPORTS_FILE = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
/**
* The path of the {@code AutoConfiguration.imports} file.
*/
public static final String IMPORTS_FILE = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
private FileCollection sourceFiles = getProject().getObjects().fileCollection();

View File

@ -65,7 +65,7 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
public static final String CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkAdditionalSpringConfigurationMetadata";
/**
* Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.
* Name of the {@link CheckSpringConfigurationMetadata} task.
*/
public static final String CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkSpringConfigurationMetadata";

View File

@ -41,7 +41,7 @@ public class OptionalDependenciesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
Configuration optional = project.getConfigurations().create("optional");
optional.setCanBeConsumed(false);
optional.setCanBeConsumed(true);
optional.setCanBeResolved(false);
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
SourceSetContainer sourceSets = project.getExtensions()

View File

@ -0,0 +1,233 @@
/*
* Copyright 2025-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.test.autoconfigure;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.springframework.boot.build.autoconfigure.AutoConfigurationClass;
/**
* Task to check the contents of a project's
* {@code META-INF/spring/*.AutoConfigure*.imports} files.
*
* @author Andy Wilkinson
*/
public abstract class CheckAutoConfigureImports extends DefaultTask {
private FileCollection sourceFiles = getProject().getObjects().fileCollection();
private FileCollection classpath = getProject().getObjects().fileCollection();
public CheckAutoConfigureImports() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
}
@InputFiles
@SkipWhenEmpty
@PathSensitive(PathSensitivity.RELATIVE)
public FileTree getSource() {
return this.sourceFiles.getAsFileTree()
.matching((filter) -> filter.include("META-INF/spring/*.AutoConfigure*.imports"));
}
public void setSource(Object source) {
this.sourceFiles = getProject().getObjects().fileCollection().from(source);
}
@Classpath
public FileCollection getClasspath() {
return this.classpath;
}
public void setClasspath(Object classpath) {
this.classpath = getProject().getObjects().fileCollection().from(classpath);
}
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@TaskAction
void execute() {
Map<String, List<String>> allProblems = new TreeMap<>();
for (AutoConfigureImports autoConfigureImports : loadImports()) {
List<String> problems = new ArrayList<>();
if (!find(autoConfigureImports.annotationName)) {
problems.add("Annotation '%s' was not found".formatted(autoConfigureImports.annotationName));
}
for (String imported : autoConfigureImports.imports) {
String importedClassName = imported;
if (importedClassName.startsWith("optional:")) {
importedClassName = importedClassName.substring("optional:".length());
}
boolean found = find(importedClassName, (input) -> {
if (!correctlyAnnotated(input)) {
problems.add("Imported auto-configuration '%s' is not annotated with @AutoConfiguration"
.formatted(imported));
}
});
if (!found) {
problems.add("Imported auto-configuration '%s' was not found".formatted(importedClassName));
}
}
List<String> sortedValues = new ArrayList<>(autoConfigureImports.imports);
Collections.sort(sortedValues, (i1, i2) -> {
boolean imported1 = i1.startsWith("optional:");
boolean imported2 = i2.startsWith("optional:");
int comparison = Boolean.compare(imported1, imported2);
if (comparison != 0) {
return comparison;
}
return i1.compareTo(i2);
});
if (!sortedValues.equals(autoConfigureImports.imports)) {
File sortedOutputFile = getOutputDirectory().file("sorted-" + autoConfigureImports.fileName)
.get()
.getAsFile();
writeString(sortedOutputFile, sortedValues.stream().collect(Collectors.joining(System.lineSeparator()))
+ System.lineSeparator());
problems.add(
"Entries should be required then optional, each sorted alphabetically (expected content written to '%s')"
.formatted(sortedOutputFile.getAbsolutePath()));
}
if (!problems.isEmpty()) {
allProblems.computeIfAbsent(autoConfigureImports.fileName, (unused) -> new ArrayList<>())
.addAll(problems);
}
}
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
writeReport(allProblems, outputFile);
if (!allProblems.isEmpty()) {
throw new VerificationException(
"AutoConfigure….imports checks failed. See '%s' for details".formatted(outputFile));
}
}
private List<AutoConfigureImports> loadImports() {
return getSource().getFiles().stream().map((file) -> {
String fileName = file.getName();
String annotationName = fileName.substring(0, fileName.length() - ".imports".length());
return new AutoConfigureImports(annotationName, loadImports(file), fileName);
}).toList();
}
private List<String> loadImports(File importsFile) {
try {
return Files.readAllLines(importsFile.toPath());
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private boolean find(String className) {
return find(className, (input) -> {
});
}
private boolean find(String className, Consumer<InputStream> handler) {
for (File root : this.classpath.getFiles()) {
String classFilePath = className.replace(".", "/") + ".class";
if (root.isDirectory()) {
File classFile = new File(root, classFilePath);
if (classFile.isFile()) {
try (InputStream input = new FileInputStream(classFile)) {
handler.accept(input);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
return true;
}
}
else {
try (JarFile jar = new JarFile(root)) {
ZipEntry entry = jar.getEntry(classFilePath);
if (entry != null) {
try (InputStream input = jar.getInputStream(entry)) {
handler.accept(input);
}
return true;
}
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}
return false;
}
private boolean correctlyAnnotated(InputStream classFile) {
return AutoConfigurationClass.of(classFile) != null;
}
private void writeReport(Map<String, List<String>> allProblems, File outputFile) {
outputFile.getParentFile().mkdirs();
StringBuilder report = new StringBuilder();
if (!allProblems.isEmpty()) {
allProblems.forEach((fileName, problems) -> {
report.append("Found problems in '%s':%n".formatted(fileName));
problems.forEach((problem) -> report.append(" - %s%n".formatted(problem)));
});
}
writeString(outputFile, report.toString());
}
private void writeString(File file, String content) {
try {
Files.writeString(file.toPath(), content);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
record AutoConfigureImports(String annotationName, List<String> imports, String fileName) {
}
}

View File

@ -17,17 +17,14 @@
package org.springframework.boot.build.test.autoconfigure;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
@ -38,9 +35,9 @@ 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 tools.jackson.databind.json.JsonMapper;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;
/**
* {@link Task} used to document test slices.
@ -49,16 +46,16 @@ import org.springframework.util.StringUtils;
*/
public abstract class DocumentTestSlices extends DefaultTask {
private FileCollection testSlices;
private FileCollection testSliceMetadata;
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public FileCollection getTestSlices() {
return this.testSlices;
return this.testSliceMetadata;
}
public void setTestSlices(FileCollection testSlices) {
this.testSlices = testSlices;
this.testSliceMetadata = testSlices;
}
@OutputFile
@ -66,61 +63,42 @@ public abstract class DocumentTestSlices extends DefaultTask {
@TaskAction
void documentTestSlices() throws IOException {
Set<TestSlice> testSlices = readTestSlices();
Map<String, List<TestSlice>> testSlices = readTestSlices();
writeTable(testSlices);
}
@SuppressWarnings("unchecked")
private Set<TestSlice> readTestSlices() throws IOException {
Set<TestSlice> testSlices = new TreeSet<>();
for (File metadataFile : this.testSlices) {
Properties metadata = new Properties();
try (Reader reader = new FileReader(metadataFile)) {
metadata.load(reader);
}
for (String name : Collections.list((Enumeration<String>) metadata.propertyNames())) {
testSlices.add(new TestSlice(name,
new TreeSet<>(StringUtils.commaDelimitedListToSet(metadata.getProperty(name)))));
}
private Map<String, List<TestSlice>> readTestSlices() {
Map<String, List<TestSlice>> testSlices = new TreeMap<>();
for (File metadataFile : this.testSliceMetadata) {
JsonMapper mapper = JsonMapper.builder().build();
TestSliceMetadata metadata = mapper.readValue(metadataFile, TestSliceMetadata.class);
List<TestSlice> slices = new ArrayList<>(metadata.testSlices());
Collections.sort(slices, (s1, s2) -> s1.annotation().compareTo(s2.annotation()));
testSlices.put(metadata.module(), slices);
}
return testSlices;
}
private void writeTable(Set<TestSlice> testSlices) throws IOException {
private void writeTable(Map<String, List<TestSlice>> testSlicesByModule) throws IOException {
File outputFile = getOutputFile().getAsFile().get();
outputFile.getParentFile().mkdirs();
try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
writer.println("[cols=\"d,a\"]");
writer.println("[cols=\"d,d,a\"]");
writer.println("|===");
writer.println("| Test slice | Imported auto-configuration");
for (TestSlice testSlice : testSlices) {
writer.println("|Module | Test slice | Imported auto-configuration");
testSlicesByModule.forEach((module, testSlices) -> {
testSlices.forEach((testSlice) -> {
writer.println();
writer.printf("| `@%s`%n", testSlice.className);
writer.printf("| `%s`%n", module);
writer.printf("| javadoc:%s[format=annotation]%n", testSlice.annotation());
writer.println("| ");
for (String importedAutoConfiguration : testSlice.importedAutoConfigurations) {
for (String importedAutoConfiguration : testSlice.importedAutoConfigurations()) {
writer.printf("`%s`%n", importedAutoConfiguration);
}
}
});
});
writer.println("|===");
}
}
private static final class TestSlice implements Comparable<TestSlice> {
private final String className;
private final SortedSet<String> importedAutoConfigurations;
private TestSlice(String className, SortedSet<String> importedAutoConfigurations) {
this.className = ClassUtils.getShortName(className);
this.importedAutoConfigurations = importedAutoConfigurations;
}
@Override
public int compareTo(TestSlice other) {
return this.className.compareTo(other.className);
}
}
}

View File

@ -0,0 +1,238 @@
/*
* 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.test.autoconfigure;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.inject.Inject;
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.model.ObjectFactory;
import org.gradle.api.tasks.Classpath;
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.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.StringUtils;
/**
* A {@link Task} for generating metadata describing a project's test slices.
*
* @author Andy Wilkinson
*/
public abstract class GenerateTestSliceMetadata extends DefaultTask {
private final ObjectFactory objectFactory;
private FileCollection classpath;
private FileCollection importsFiles;
private FileCollection classesDirs;
@Inject
public GenerateTestSliceMetadata(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
public void setSourceSet(SourceSet sourceSet) {
this.classpath = sourceSet.getRuntimeClasspath();
this.importsFiles = this.objectFactory.fileTree()
.from(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring"));
this.importsFiles.filter((file) -> file.getName().endsWith(".imports"));
getSpringFactories().set(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
this.classesDirs = sourceSet.getOutput().getClassesDirs();
}
@OutputFile
public abstract RegularFileProperty getOutputFile();
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
abstract RegularFileProperty getSpringFactories();
@Classpath
FileCollection getClasspath() {
return this.classpath;
}
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
FileCollection getImportFiles() {
return this.importsFiles;
}
@Classpath
FileCollection getClassesDirs() {
return this.classesDirs;
}
@TaskAction
void generateTestSliceMetadata() throws IOException {
TestSliceMetadata metadata = readTestSlices();
File outputFile = getOutputFile().getAsFile().get();
outputFile.getParentFile().mkdirs();
metadata.writeTo(outputFile);
}
private TestSliceMetadata readTestSlices() throws IOException {
List<TestSlice> testSlices = new ArrayList<>();
try (URLClassLoader classLoader = new URLClassLoader(
StreamSupport.stream(this.classpath.spliterator(), false).map(this::toURL).toArray(URL[]::new))) {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader);
Properties springFactories = readSpringFactories(getSpringFactories().getAsFile().getOrNull());
readImportsFiles(springFactories, this.importsFiles);
for (File classesDir : this.classesDirs) {
testSlices.addAll(readTestSlices(classesDir, metadataReaderFactory, springFactories));
}
}
return new TestSliceMetadata(getProject().getName(), testSlices);
}
/**
* Reads the given imports files and puts them in springFactories. The key is the file
* name, the value is the file contents, split by line, delimited with a comma. This
* is done to mimic the spring.factories structure.
* @param springFactories spring.factories parsed as properties
* @param importsFiles the imports files to read
*/
private void readImportsFiles(Properties springFactories, FileCollection importsFiles) {
for (File file : importsFiles.getFiles()) {
try {
List<String> lines = removeComments(Files.readAllLines(file.toPath()));
String fileNameWithoutExtension = file.getName()
.substring(0, file.getName().length() - ".imports".length());
springFactories.setProperty(fileNameWithoutExtension,
StringUtils.collectionToCommaDelimitedString(lines));
}
catch (IOException ex) {
throw new UncheckedIOException("Failed to read file " + file, ex);
}
}
}
private List<String> removeComments(List<String> lines) {
List<String> result = new ArrayList<>();
for (String line : lines) {
int commentIndex = line.indexOf('#');
if (commentIndex > -1) {
line = line.substring(0, commentIndex);
}
line = line.trim();
if (!line.isEmpty()) {
result.add(line);
}
}
return result;
}
private URL toURL(File file) {
try {
return file.toURI().toURL();
}
catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
}
private Properties readSpringFactories(File file) throws IOException {
Properties springFactories = new Properties();
if (file.isFile()) {
try (Reader in = new FileReader(file)) {
springFactories.load(in);
}
}
return springFactories;
}
private List<TestSlice> readTestSlices(File classesDir, MetadataReaderFactory metadataReaderFactory,
Properties springFactories) throws IOException {
try (Stream<Path> classes = Files.walk(classesDir.toPath())) {
return classes.filter((path) -> path.toString().endsWith("Test.class"))
.map((path) -> getMetadataReader(path, metadataReaderFactory))
.filter((metadataReader) -> metadataReader.getClassMetadata().isAnnotation())
.map((metadataReader) -> readTestSlice(metadataReader, springFactories))
.toList();
}
}
private MetadataReader getMetadataReader(Path path, MetadataReaderFactory metadataReaderFactory) {
try {
return metadataReaderFactory.getMetadataReader(new FileSystemResource(path));
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private TestSlice readTestSlice(MetadataReader metadataReader, Properties springFactories) {
String annotationName = metadataReader.getClassMetadata().getClassName();
List<String> importedAutoConfiguration = getImportedAutoConfiguration(springFactories,
metadataReader.getAnnotationMetadata());
return new TestSlice(annotationName, importedAutoConfiguration);
}
private List<String> getImportedAutoConfiguration(Properties springFactories,
AnnotationMetadata annotationMetadata) {
Stream<String> importers = findMetaImporters(annotationMetadata);
if (annotationMetadata.isAnnotated("org.springframework.boot.autoconfigure.ImportAutoConfiguration")) {
importers = Stream.concat(importers, Stream.of(annotationMetadata.getClassName()));
}
return importers
.flatMap((importer) -> StringUtils.commaDelimitedListToSet(springFactories.getProperty(importer)).stream())
.toList();
}
private Stream<String> findMetaImporters(AnnotationMetadata annotationMetadata) {
return annotationMetadata.getAnnotationTypes()
.stream()
.filter((annotationType) -> isAutoConfigurationImporter(annotationType, annotationMetadata));
}
private boolean isAutoConfigurationImporter(String annotationType, AnnotationMetadata metadata) {
return metadata.getMetaAnnotationTypes(annotationType)
.contains("org.springframework.boot.autoconfigure.ImportAutoConfiguration");
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.test.autoconfigure;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
/**
* {@link Plugin} for projects that define test auto-configuration. When the
* {@link JavaPlugin} is applied it:
*
* <ul>
* <li>Add checks to ensure AutoConfigure*.import files and related annotations are
* correct</li>
* </ul>
*
* @author Andy Wilkinson
*/
public class TestAutoConfigurationPlugin implements Plugin<Project> {
@Override
public void apply(Project target) {
target.getPlugins().withType(JavaPlugin.class, (plugin) -> {
target.getTasks().register("checkAutoConfigureImports", CheckAutoConfigureImports.class, (task) -> {
SourceSet mainSourceSet = target.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
task.setSource(mainSourceSet.getResources());
ConfigurableFileCollection classpath = target.files(mainSourceSet.getRuntimeClasspath(),
target.getConfigurations().getByName(mainSourceSet.getRuntimeClasspathConfigurationName()));
task.setClasspath(classpath);
});
});
}
}

View File

@ -17,229 +17,30 @@
package org.springframework.boot.build.test.autoconfigure;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.inject.Inject;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.InputFile;
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.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.springframework.core.CollectionFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.StringUtils;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
/**
* A {@link Task} for generating metadata describing a project's test slices.
* Metadata describing a module's test slices.
*
* @param module the module's name
* @param testSlices the module's test slices
* @author Andy Wilkinson
*/
public abstract class TestSliceMetadata extends DefaultTask {
record TestSliceMetadata(String module, List<TestSlice> testSlices) {
private final ObjectFactory objectFactory;
private FileCollection classpath;
private FileCollection importsFiles;
private FileCollection classesDirs;
@Inject
public TestSliceMetadata(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
Configuration testSliceMetadata = getProject().getConfigurations().maybeCreate("testSliceMetadata");
getProject().afterEvaluate((evaluated) -> evaluated.getArtifacts()
.add(testSliceMetadata.getName(), getOutputFile(), (artifact) -> artifact.builtBy(this)));
static TestSliceMetadata readFrom(File file) {
return JsonMapper.builder().build().readValue(file, TestSliceMetadata.class);
}
public void setSourceSet(SourceSet sourceSet) {
this.classpath = sourceSet.getRuntimeClasspath();
this.importsFiles = this.objectFactory.fileTree()
.from(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring"));
this.importsFiles.filter((file) -> file.getName().endsWith(".imports"));
getSpringFactories().set(new File(sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
this.classesDirs = sourceSet.getOutput().getClassesDirs();
void writeTo(File file) {
JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build().writeValue(file, this);
}
@OutputFile
public abstract RegularFileProperty getOutputFile();
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
abstract RegularFileProperty getSpringFactories();
@Classpath
FileCollection getClasspath() {
return this.classpath;
}
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
FileCollection getImportFiles() {
return this.importsFiles;
}
@Classpath
FileCollection getClassesDirs() {
return this.classesDirs;
}
@TaskAction
void documentTestSlices() throws IOException {
Properties testSlices = readTestSlices();
File outputFile = getOutputFile().getAsFile().get();
outputFile.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(outputFile)) {
testSlices.store(writer, null);
}
}
private Properties readTestSlices() throws IOException {
Properties testSlices = CollectionFactory.createSortedProperties(true);
try (URLClassLoader classLoader = new URLClassLoader(
StreamSupport.stream(this.classpath.spliterator(), false).map(this::toURL).toArray(URL[]::new))) {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader);
Properties springFactories = readSpringFactories(getSpringFactories().getAsFile().get());
readImportsFiles(springFactories, this.importsFiles);
for (File classesDir : this.classesDirs) {
addTestSlices(testSlices, classesDir, metadataReaderFactory, springFactories);
}
}
return testSlices;
}
/**
* Reads the given imports files and puts them in springFactories. The key is the file
* name, the value is the file contents, split by line, delimited with a comma. This
* is done to mimic the spring.factories structure.
* @param springFactories spring.factories parsed as properties
* @param importsFiles the imports files to read
*/
private void readImportsFiles(Properties springFactories, FileCollection importsFiles) {
for (File file : importsFiles.getFiles()) {
try {
List<String> lines = removeComments(Files.readAllLines(file.toPath()));
String fileNameWithoutExtension = file.getName()
.substring(0, file.getName().length() - ".imports".length());
springFactories.setProperty(fileNameWithoutExtension,
StringUtils.collectionToCommaDelimitedString(lines));
}
catch (IOException ex) {
throw new UncheckedIOException("Failed to read file " + file, ex);
}
}
}
private List<String> removeComments(List<String> lines) {
List<String> result = new ArrayList<>();
for (String line : lines) {
int commentIndex = line.indexOf('#');
if (commentIndex > -1) {
line = line.substring(0, commentIndex);
}
line = line.trim();
if (!line.isEmpty()) {
result.add(line);
}
}
return result;
}
private URL toURL(File file) {
try {
return file.toURI().toURL();
}
catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
}
private Properties readSpringFactories(File file) throws IOException {
Properties springFactories = new Properties();
try (Reader in = new FileReader(file)) {
springFactories.load(in);
}
return springFactories;
}
private void addTestSlices(Properties testSlices, File classesDir, MetadataReaderFactory metadataReaderFactory,
Properties springFactories) throws IOException {
try (Stream<Path> classes = Files.walk(classesDir.toPath())) {
classes.filter((path) -> path.toString().endsWith("Test.class"))
.map((path) -> getMetadataReader(path, metadataReaderFactory))
.filter((metadataReader) -> metadataReader.getClassMetadata().isAnnotation())
.forEach((metadataReader) -> addTestSlice(testSlices, springFactories, metadataReader));
}
record TestSlice(String annotation, List<String> importedAutoConfigurations) {
}
private MetadataReader getMetadataReader(Path path, MetadataReaderFactory metadataReaderFactory) {
try {
return metadataReaderFactory.getMetadataReader(new FileSystemResource(path));
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private void addTestSlice(Properties testSlices, Properties springFactories, MetadataReader metadataReader) {
testSlices.setProperty(metadataReader.getClassMetadata().getClassName(),
StringUtils.collectionToCommaDelimitedString(
getImportedAutoConfiguration(springFactories, metadataReader.getAnnotationMetadata())));
}
private SortedSet<String> getImportedAutoConfiguration(Properties springFactories,
AnnotationMetadata annotationMetadata) {
Stream<String> importers = findMetaImporters(annotationMetadata);
if (annotationMetadata.isAnnotated("org.springframework.boot.autoconfigure.ImportAutoConfiguration")) {
importers = Stream.concat(importers, Stream.of(annotationMetadata.getClassName()));
}
return importers
.flatMap((importer) -> StringUtils.commaDelimitedListToSet(springFactories.getProperty(importer)).stream())
.collect(Collectors.toCollection(TreeSet::new));
}
private Stream<String> findMetaImporters(AnnotationMetadata annotationMetadata) {
return annotationMetadata.getAnnotationTypes()
.stream()
.filter((annotationType) -> isAutoConfigurationImporter(annotationType, annotationMetadata));
}
private boolean isAutoConfigurationImporter(String annotationType, AnnotationMetadata metadata) {
return metadata.getMetaAnnotationTypes(annotationType)
.contains("org.springframework.boot.autoconfigure.ImportAutoConfiguration");
}
}

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.test.autoconfigure;
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.plugins.PluginContainer;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
/**
* {@link Plugin} for projects that define one or more test slices. When applied, it:
*
* <ul>
* <li>Applies the {@link TestAutoConfigurationPlugin}
* </ul>
* Additionally, when the {@link JavaPlugin} is applied it:
*
* <ul>
* <li>Defines a task that produces metadata describing the test slices. The metadata is
* made available as an artifact in the {@code testSliceMetadata} configuration
* </ul>
*
* @author Andy Wilkinson
*/
public class TestSlicePlugin implements Plugin<Project> {
private static final String TEST_SLICE_METADATA_CONFIGURATION_NAME = "testSliceMetadata";
@Override
public void apply(Project target) {
PluginContainer plugins = target.getPlugins();
plugins.apply(TestAutoConfigurationPlugin.class);
plugins.withType(JavaPlugin.class, (plugin) -> {
TaskProvider<GenerateTestSliceMetadata> generateTestSliceMetadata = target.getTasks()
.register("generateTestSliceMetadata", GenerateTestSliceMetadata.class, (task) -> {
SourceSet mainSourceSet = target.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
task.setSourceSet(mainSourceSet);
task.getOutputFile().set(target.getLayout().getBuildDirectory().file("test-slice-metadata.json"));
});
addMetadataArtifact(target, generateTestSliceMetadata);
});
}
private void addMetadataArtifact(Project project, TaskProvider<GenerateTestSliceMetadata> task) {
project.getConfigurations().consumable(TEST_SLICE_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, "test-slice-metadata"));
});
});
project.getArtifacts().add(TEST_SLICE_METADATA_CONFIGURATION_NAME, task);
}
}

View File

@ -116,6 +116,18 @@ apiref-openjdk=https://docs.oracle.com/en/java/javase/17/docs/api
# === Code Links ===
code-spring-boot=https://github.com/{github-repo}/tree/{github-ref}
code-spring-boot-autoconfigure-src={code-spring-boot}/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure
code-spring-boot-autoconfigure-src={code-spring-boot}/core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure
code-spring-boot-batch-jdbc-src={code-spring-boot}/module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc
code-spring-boot-batch-src={code-spring-boot}/module/spring-boot-batch/src/main/java/org/springframework/boot/batch
code-spring-boot-freemarker-src={code-spring-boot}/module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker
code-spring-boot-groovy-templates-src={code-spring-boot}/module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template
code-spring-boot-hibernate-src={code-spring-boot}/module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate
code-spring-boot-integration-src={code-spring-boot}/module/spring-boot-integration/src/main/java/org/springframework/boot/integration
code-spring-boot-jdbc-src={code-spring-boot}/module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc
code-spring-boot-jooq-src={code-spring-boot}/module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq
code-spring-boot-jpa-src={code-spring-boot}/module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa
code-spring-boot-latest=https://github.com/{github-repo}/tree/main
code-spring-boot-servlet-src={code-spring-boot}/module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet
code-spring-boot-thymeleaf-src={code-spring-boot}/module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf
code-spring-boot-webmvc-src={code-spring-boot}/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc

View File

@ -77,7 +77,9 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("java {");
out.println(" sourceCompatibility = '17'");
out.println("}");
out.println("description 'Test project for manifest customization'");
out.println("jar.archiveFileName = 'test.jar'");
}
@ -107,7 +109,9 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("java {");
out.println(" sourceCompatibility = '17'");
out.println("}");
out.println("description 'Test'");
}
runGradle("assemble");
@ -136,7 +140,9 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("java {");
out.println(" sourceCompatibility = '17'");
out.println("}");
out.println("description 'Test'");
}
runGradle("assemble");

View File

@ -31,6 +31,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.jupiter.params.support.ParameterDeclarations;
import static org.assertj.core.api.Assertions.assertThat;
@ -244,7 +245,8 @@ class DependencyVersionUpgradeTests {
static class InputProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
public Stream<? extends Arguments> provideArguments(ParameterDeclarations parameterDeclarations,
ExtensionContext context) {
Method testMethod = context.getRequiredTestMethod();
Stream<Arguments> artifactVersions = artifactVersions(testMethod)
.map((artifactVersion) -> Arguments.of(VersionType.ARTIFACT_VERSION.parse(artifactVersion.current()),

View File

@ -0,0 +1,50 @@
/*
* 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.test.autoconfigure;
import java.io.File;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TestSliceMetadata}.
*
* @author Andy Wilkinson
*/
public class TestSliceMetadataTests {
@TempDir
private File temp;
@Test
void roundtripJson() {
TestSliceMetadata source = new TestSliceMetadata("example",
List.of(new TestSlice("ExampleOneTest", List.of("com.example.OneAutoConfiguration")),
new TestSlice("ExampleTwoTest", List.of("com.example.TwoAutoConfiguration"))));
File metadataFile = new File(this.temp, "metadata.json");
source.writeTo(metadataFile);
TestSliceMetadata readBack = TestSliceMetadata.readFrom(metadataFile);
assertThat(source).isEqualTo(readBack);
}
}

View File

@ -166,6 +166,7 @@ class TestFailuresPluginIntegrationTests {
writer.println("dependencies {");
writer.println(" testImplementation 'org.junit.jupiter:junit-jupiter:5.6.0'");
writer.println(" testImplementation 'org.assertj:assertj-core:3.11.1'");
writer.println(" testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.6.0'");
writer.println("}");
writer.println();
writer.println("test {");

View File

@ -21,11 +21,11 @@ import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;

View File

@ -21,7 +21,7 @@ import java.util.stream.IntStream;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.ApiVersion;
import org.springframework.util.StringUtils;
/**

View File

@ -21,11 +21,11 @@ import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;

View File

@ -28,8 +28,8 @@ import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.Owner;
import org.springframework.boot.buildpack.platform.io.TarArchive;

View File

@ -24,6 +24,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.DockerApi;
import org.springframework.boot.buildpack.platform.docker.DockerLog;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
import org.springframework.boot.buildpack.platform.docker.TotalProgressPushListener;
@ -34,7 +35,6 @@ import org.springframework.boot.buildpack.platform.docker.transport.DockerEngine
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageArchive;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.IOBiConsumer;
import org.springframework.boot.buildpack.platform.io.TarArchive;

View File

@ -28,10 +28,10 @@ import com.sun.jna.Platform;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.build.Cache.Bind;
import org.springframework.boot.buildpack.platform.docker.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.DockerApi;
import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;
import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
import org.springframework.boot.buildpack.platform.docker.type.ContainerContent;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.buildpack.platform.docker.type;
package org.springframework.boot.buildpack.platform.docker;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -28,7 +28,7 @@ import org.springframework.util.Assert;
*
* @author Phillip Webb
* @author Scott Frederick
* @since 3.4.0
* @since 4.0.0
*/
public final class ApiVersion {

View File

@ -34,14 +34,12 @@ import org.springframework.boot.buildpack.platform.docker.PushImageUpdateEvent.E
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
import org.springframework.boot.buildpack.platform.docker.type.ContainerContent;
import org.springframework.boot.buildpack.platform.docker.type.ContainerReference;
import org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageArchive;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
import org.springframework.boot.buildpack.platform.io.IOBiConsumer;

View File

@ -14,19 +14,20 @@
* limitations under the License.
*/
package org.springframework.boot.buildpack.platform.docker.type;
package org.springframework.boot.buildpack.platform.docker;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.util.Assert;
/**
* A platform specification for a Docker image.
*
* @author Scott Frederick
* @since 3.4.0
* @since 4.0.0
*/
public class ImagePlatform {

View File

@ -20,7 +20,7 @@ import java.util.stream.IntStream;
import org.junit.jupiter.api.Test;
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.ApiVersion;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

View File

@ -37,9 +37,9 @@ import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
import org.springframework.boot.buildpack.platform.docker.type.ImageName;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.Owner;
import org.springframework.boot.buildpack.platform.io.TarArchive;

View File

@ -31,6 +31,7 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi
import org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;
import org.springframework.boot.buildpack.platform.docker.DockerLog;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;
import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;
@ -39,7 +40,6 @@ import org.springframework.boot.buildpack.platform.docker.type.ContainerReferenc
import org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageArchive;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.TarArchive;

View File

@ -41,6 +41,7 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;
import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;
import org.springframework.boot.buildpack.platform.docker.type.Binding;
@ -48,7 +49,6 @@ import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
import org.springframework.boot.buildpack.platform.docker.type.ContainerContent;
import org.springframework.boot.buildpack.platform.docker.type.ContainerReference;
import org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
import org.springframework.boot.buildpack.platform.io.IOConsumer;

View File

@ -25,10 +25,10 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.buildpack.platform.docker.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;
import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
import org.springframework.util.FileCopyUtils;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.buildpack.platform.docker.type;
package org.springframework.boot.buildpack.platform.docker;
import java.util.Arrays;

View File

@ -45,14 +45,12 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi.SystemApi;
import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;
import org.springframework.boot.buildpack.platform.docker.type.ContainerContent;
import org.springframework.boot.buildpack.platform.docker.type.ContainerReference;
import org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageArchive;
import org.springframework.boot.buildpack.platform.docker.type.ImagePlatform;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.docker.type.VolumeName;
import org.springframework.boot.buildpack.platform.io.Content;

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.buildpack.platform.docker.type;
package org.springframework.boot.buildpack.platform.docker;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
import static org.assertj.core.api.Assertions.assertThat;
@ -64,7 +65,7 @@ class ImagePlatformTests extends AbstractJsonTests {
}
private Image getImage() throws IOException {
return Image.of(getContent("image.json"));
return Image.of(getContent("type/image.json"));
}
}

View File

@ -79,4 +79,7 @@
<suppress files="EntityManagerFactoryBuilder\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
<suppress files="DockerApi\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
<suppress files="InvocationContext\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
<!-- https://github.com/apache/logging-log4j2/issues/2769#issuecomment-3049020222 -->
<suppress files="SpringProfileArbiter\.java" checks="SpringMethodVisibility"/>
<suppress files="StructuredLogLayout\.java" checks="SpringMethodVisibility"/>
</suppressions>

View File

@ -6,7 +6,10 @@
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/checkstyle-suppressions.xml"/>
</module>
<module name="io.spring.javaformat.checkstyle.SpringChecks" />
<module name="io.spring.javaformat.checkstyle.SpringChecks">
<property name="avoidStaticImportExcludes"
value="org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration" />
</module>
<module name="io.spring.javaformat.checkstyle.check.SpringHeaderCheck">
<property name="headerFile" value="${config_loc}/checkstyle-header.txt"/>
</module>

View File

@ -17,7 +17,7 @@
<subpackage name="ansi">
<disallow pkg="org.springframework.boot" exact-match="true"/>
</subpackage>
<subpackage name="avilability">
<subpackage name="availability">
<disallow pkg="org.springframework.boot" exact-match="true"/>
</subpackage>
<subpackage name="bootstrap">
@ -91,8 +91,6 @@
<disallow pkg="jakarta.servlet" />
<!-- Common -->
<subpackage name="client">
</subpackage>
<subpackage name="context">
<allow pkg="org.springframework.context" />
<subpackage name="servlet">
@ -111,6 +109,10 @@
<allow pkg="org.springframework.boot.web.servlet" />
</subpackage>
</subpackage>
<subpackage name="client">
<allow pkg="jakarta.servlet" />
<allow pkg="org.springframework.context" />
</subpackage>
<subpackage name="context">
<allow pkg="org.springframework.context" />
</subpackage>

View File

@ -19,7 +19,7 @@ style:
active: true
NewLineAtEndOfFile:
active: true
UnusedImports:
UnusedImport:
active: true
WildcardImport:
active: true

View File

@ -136,6 +136,7 @@ def dependenciesOf(String version) {
modules += [
"spring-boot-jersey"
]
}
if (version.equals("4.0.0-M1")) {
modules += [
"spring-boot-metrics",
@ -150,6 +151,10 @@ def dependenciesOf(String version) {
"spring-boot-micrometer-tracing"
]
}
if (version.equals("4.0.0-RC1")) {
modules += [
"spring-boot-batch-jdbc"
]
}
return modules
}

View File

@ -56,3 +56,7 @@ dependencies {
test {
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
}
tasks.named("compileTestJava") {
options.nullability.checking = "tests"
}

View File

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure;
import java.util.Collections;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -42,7 +43,7 @@ class AutoConfigurationExcludeFilterTests {
private static final Class<?> FILTERED = ExampleFilteredAutoConfiguration.class;
private AnnotationConfigApplicationContext context;
private @Nullable AnnotationConfigApplicationContext context;
@AfterEach
void cleanUp() {
@ -56,7 +57,10 @@ class AutoConfigurationExcludeFilterTests {
this.context = new AnnotationConfigApplicationContext(Config.class);
assertThat(this.context.getBeansOfType(String.class)).hasSize(1);
assertThat(this.context.getBean(String.class)).isEqualTo("test");
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> this.context.getBean(FILTERED));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
assertThat(this.context).isNotNull();
this.context.getBean(FILTERED);
});
}
@Configuration(proxyBeanMethods = false)

View File

@ -28,6 +28,7 @@ import java.util.Set;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -83,39 +84,35 @@ class AutoConfigurationImportSelectorTests {
void importsAreSelectedWhenUsingEnableAutoConfiguration() {
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSameSizeAs(getAutoConfigurationClassNames());
assertThat(this.importSelector.getLastEvent().getExclusions()).isEmpty();
assertThat(getLastEvent().getExclusions()).isEmpty();
}
@Test
void classExclusionsAreApplied() {
String[] imports = selectImports(EnableAutoConfigurationWithClassExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(SeventhAutoConfiguration.class.getName());
assertThat(getLastEvent().getExclusions()).contains(SeventhAutoConfiguration.class.getName());
}
@Test
void classExclusionsAreAppliedWhenUsingSpringBootApplication() {
String[] imports = selectImports(SpringBootApplicationWithClassExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains(SeventhAutoConfiguration.class.getName());
assertThat(getLastEvent().getExclusions()).contains(SeventhAutoConfiguration.class.getName());
}
@Test
void classNamesExclusionsAreApplied() {
String[] imports = selectImports(EnableAutoConfigurationWithClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains("com.example.one.FirstAutoConfiguration");
assertThat(getLastEvent().getExclusions()).contains("com.example.one.FirstAutoConfiguration");
}
@Test
void classNamesExclusionsAreAppliedWhenUsingSpringBootApplication() {
String[] imports = selectImports(SpringBootApplicationWithClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains("com.example.three.ThirdAutoConfiguration");
assertThat(getLastEvent().getExclusions()).contains("com.example.three.ThirdAutoConfiguration");
}
@Test
@ -123,8 +120,7 @@ class AutoConfigurationImportSelectorTests {
this.environment.setProperty("spring.autoconfigure.exclude", "com.example.three.ThirdAutoConfiguration");
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains("com.example.three.ThirdAutoConfiguration");
assertThat(getLastEvent().getExclusions()).contains("com.example.three.ThirdAutoConfiguration");
}
@Test
@ -151,8 +147,8 @@ class AutoConfigurationImportSelectorTests {
private void testSeveralPropertyExclusionsAreApplied() {
String[] imports = selectImports(BasicEnableAutoConfiguration.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 2);
assertThat(this.importSelector.getLastEvent().getExclusions())
.contains("com.example.two.SecondAutoConfiguration", "com.example.four.FourthAutoConfiguration");
assertThat(getLastEvent().getExclusions()).contains("com.example.two.SecondAutoConfiguration",
"com.example.four.FourthAutoConfiguration");
}
@Test
@ -160,9 +156,8 @@ class AutoConfigurationImportSelectorTests {
this.environment.setProperty("spring.autoconfigure.exclude", "com.example.one.FirstAutoConfiguration");
String[] imports = selectImports(EnableAutoConfigurationWithClassAndClassNameExclusions.class);
assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 3);
assertThat(this.importSelector.getLastEvent().getExclusions()).contains(
"com.example.one.FirstAutoConfiguration", "com.example.five.FifthAutoConfiguration",
SeventhAutoConfiguration.class.getName());
assertThat(getLastEvent().getExclusions()).contains("com.example.one.FirstAutoConfiguration",
"com.example.five.FifthAutoConfiguration", SeventhAutoConfiguration.class.getName());
}
@Test
@ -202,7 +197,7 @@ class AutoConfigurationImportSelectorTests {
this.environment.setProperty("spring.autoconfigure.exclude",
"org.springframework.boot.autoconfigure.DoesNotExist2");
selectImports(EnableAutoConfigurationWithAbsentClassNameExclude.class);
assertThat(this.importSelector.getLastEvent().getExclusions()).containsExactlyInAnyOrder(
assertThat(getLastEvent().getExclusions()).containsExactlyInAnyOrder(
"org.springframework.boot.autoconfigure.DoesNotExist1",
"org.springframework.boot.autoconfigure.DoesNotExist2");
}
@ -269,11 +264,17 @@ class AutoConfigurationImportSelectorTests {
importSelector.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
}
private AutoConfigurationImportEvent getLastEvent() {
AutoConfigurationImportEvent result = this.importSelector.getLastEvent();
assertThat(result).isNotNull();
return result;
}
private final class TestAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
private AutoConfigurationImportEvent lastEvent;
private @Nullable AutoConfigurationImportEvent lastEvent;
TestAutoConfigurationImportSelector(Class<?> autoConfigurationAnnotation) {
TestAutoConfigurationImportSelector(@Nullable Class<?> autoConfigurationAnnotation) {
super(autoConfigurationAnnotation);
}
@ -287,7 +288,7 @@ class AutoConfigurationImportSelectorTests {
return Collections.singletonList((event) -> this.lastEvent = event);
}
AutoConfigurationImportEvent getLastEvent() {
@Nullable AutoConfigurationImportEvent getLastEvent() {
return this.lastEvent;
}
@ -297,6 +298,7 @@ class AutoConfigurationImportSelectorTests {
private final Set<String> nonMatching = new HashSet<>();
@SuppressWarnings("NullAway.Init")
private BeanFactory beanFactory;
TestAutoConfigurationImportFilter(String[] configurations, int... nonMatching) {
@ -306,7 +308,8 @@ class AutoConfigurationImportSelectorTests {
}
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
public boolean[] match(@Nullable String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] result = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < result.length; i++) {
result[i] = !this.nonMatching.contains(autoConfigurationClasses[i]);

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.function.UnaryOperator;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -251,10 +252,14 @@ class AutoConfigurationSorterTests {
}
private void addAutoConfigureAfter(Properties properties, String className, AnnotationMetadata annotationMetadata) {
Map<String, Object> autoConfigureAfter = annotationMetadata
Map<String, @Nullable Object> autoConfigureAfter = annotationMetadata
.getAnnotationAttributes(AutoConfigureAfter.class.getName(), true);
if (autoConfigureAfter != null) {
String value = merge((String[]) autoConfigureAfter.get("value"), (String[]) autoConfigureAfter.get("name"));
String[] valueAttribute = (String[]) autoConfigureAfter.get("value");
String[] nameAttribute = (String[]) autoConfigureAfter.get("name");
assertThat(valueAttribute).isNotNull();
assertThat(nameAttribute).isNotNull();
String value = merge(valueAttribute, nameAttribute);
if (!value.isEmpty()) {
properties.put(className + ".AutoConfigureAfter", value);
}
@ -263,11 +268,14 @@ class AutoConfigurationSorterTests {
private void addAutoConfigureBefore(Properties properties, String className,
AnnotationMetadata annotationMetadata) {
Map<String, Object> autoConfigureBefore = annotationMetadata
Map<String, @Nullable Object> autoConfigureBefore = annotationMetadata
.getAnnotationAttributes(AutoConfigureBefore.class.getName(), true);
if (autoConfigureBefore != null) {
String value = merge((String[]) autoConfigureBefore.get("value"),
(String[]) autoConfigureBefore.get("name"));
String[] valueAttribute = (String[]) autoConfigureBefore.get("value");
String[] nameAttribute = (String[]) autoConfigureBefore.get("name");
assertThat(valueAttribute).isNotNull();
assertThat(nameAttribute).isNotNull();
String value = merge(valueAttribute, nameAttribute);
if (!value.isEmpty()) {
properties.put(className + ".AutoConfigureBefore", value);
}
@ -275,7 +283,7 @@ class AutoConfigurationSorterTests {
}
private void addAutoConfigureOrder(Properties properties, String className, AnnotationMetadata annotationMetadata) {
Map<String, Object> autoConfigureOrder = annotationMetadata
Map<String, @Nullable Object> autoConfigureOrder = annotationMetadata
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
if (autoConfigureOrder != null) {
Integer order = (Integer) autoConfigureOrder.get("order");

View File

@ -16,11 +16,13 @@
package org.springframework.boot.autoconfigure;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.FactoryBean;
public class EarlyInitFactoryBean implements FactoryBean<String> {
private String propertyFromConfig;
private @Nullable String propertyFromConfig;
public void setPropertyFromConfig(String propertyFromConfig) {
this.propertyFromConfig = propertyFromConfig;
@ -32,12 +34,12 @@ public class EarlyInitFactoryBean implements FactoryBean<String> {
}
@Override
public Class<?> getObjectType() {
public @Nullable Class<?> getObjectType() {
return null;
}
@Override
public String getObject() throws Exception {
public @Nullable String getObject() throws Exception {
return this.propertyFromConfig;
}

View File

@ -57,6 +57,7 @@ class SharedMetadataReaderFactoryContextInitializerTests {
.getField(application, "initializers");
// Simulate what would happen if an initializer was added using spring.factories
// and happened to be loaded first
assertThat(initializers).isNotNull();
initializers.add(0, new Initializer());
GenericApplicationContext context = (GenericApplicationContext) application.run();
BeanDefinition definition = context.getBeanDefinition(SharedMetadataReaderFactoryContextInitializer.BEAN_NAME);

View File

@ -44,7 +44,9 @@ class AbstractNestedConditionTests {
void invalidMemberPhase() {
this.contextRunner.withUserConfiguration(InvalidConfig.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure().getCause()).isInstanceOf(IllegalStateException.class)
Throwable startupFailure = context.getStartupFailure();
assertThat(startupFailure).isNotNull();
assertThat(startupFailure.getCause()).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Nested condition " + InvalidNestedCondition.class.getName()
+ " uses a configuration phase that is inappropriate for class "
+ OnBeanCondition.class.getName());
@ -55,7 +57,9 @@ class AbstractNestedConditionTests {
void invalidNestedMemberPhase() {
this.contextRunner.withUserConfiguration(DoubleNestedConfig.class).run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure().getCause()).isInstanceOf(IllegalStateException.class)
Throwable startupFailure = context.getStartupFailure();
assertThat(startupFailure).isNotNull();
assertThat(startupFailure.getCause()).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Nested condition " + DoubleNestedCondition.class.getName()
+ " uses a configuration phase that is inappropriate for class "
+ ValidNestedCondition.class.getName());

View File

@ -20,12 +20,14 @@ import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@ -61,19 +63,22 @@ class ConditionEvaluationReportTests {
private ConditionEvaluationReport report;
@Mock
@SuppressWarnings("NullAway.Init")
private Condition condition1;
@Mock
@SuppressWarnings("NullAway.Init")
private Condition condition2;
@Mock
@SuppressWarnings("NullAway.Init")
private Condition condition3;
private ConditionOutcome outcome1;
private @Nullable ConditionOutcome outcome1;
private ConditionOutcome outcome2;
private @Nullable ConditionOutcome outcome2;
private ConditionOutcome outcome3;
private @Nullable ConditionOutcome outcome3;
@BeforeEach
void setup() {
@ -90,21 +95,25 @@ class ConditionEvaluationReportTests {
@Test
void parent() {
this.beanFactory.setParentBeanFactory(new DefaultListableBeanFactory());
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) this.beanFactory.getParentBeanFactory());
BeanFactory parentBeanFactory = this.beanFactory.getParentBeanFactory();
assertThat(parentBeanFactory).isNotNull();
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);
assertThat(this.report).isSameAs(ConditionEvaluationReport.get(this.beanFactory));
assertThat(this.report).isNotNull();
assertThat(this.report.getParent()).isNotNull();
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) this.beanFactory.getParentBeanFactory());
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);
assertThat(this.report).isSameAs(ConditionEvaluationReport.get(this.beanFactory));
assertThat(this.report.getParent()).isSameAs(ConditionEvaluationReport
.get((ConfigurableListableBeanFactory) this.beanFactory.getParentBeanFactory()));
assertThat(this.report.getParent())
.isSameAs(ConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory));
}
@Test
void parentBottomUp() {
this.beanFactory = new DefaultListableBeanFactory(); // NB: overrides setup
this.beanFactory.setParentBeanFactory(new DefaultListableBeanFactory());
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) this.beanFactory.getParentBeanFactory());
BeanFactory parentBeanFactory = this.beanFactory.getParentBeanFactory();
assertThat(parentBeanFactory).isNotNull();
ConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);
this.report = ConditionEvaluationReport.get(this.beanFactory);
assertThat(this.report).isNotNull();
assertThat(this.report).isNotSameAs(this.report.getParent());
@ -122,7 +131,9 @@ class ConditionEvaluationReportTests {
this.report.recordConditionEvaluation("b", this.condition3, this.outcome3);
Map<String, ConditionAndOutcomes> map = this.report.getConditionAndOutcomesBySource();
assertThat(map).hasSize(2);
Iterator<ConditionAndOutcome> iterator = map.get("a").iterator();
ConditionAndOutcomes a = map.get("a");
assertThat(a).isNotNull();
Iterator<ConditionAndOutcome> iterator = a.iterator();
ConditionAndOutcome conditionAndOutcome = iterator.next();
assertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition1);
assertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome1);
@ -130,7 +141,9 @@ class ConditionEvaluationReportTests {
assertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition2);
assertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome2);
assertThat(iterator.hasNext()).isFalse();
iterator = map.get("b").iterator();
ConditionAndOutcomes b = map.get("b");
assertThat(b).isNotNull();
iterator = b.iterator();
conditionAndOutcome = iterator.next();
assertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition3);
assertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome3);
@ -140,13 +153,17 @@ class ConditionEvaluationReportTests {
@Test
void fullMatch() {
prepareMatches(true, true, true);
assertThat(this.report.getConditionAndOutcomesBySource().get("a").isFullMatch()).isTrue();
ConditionAndOutcomes a = this.report.getConditionAndOutcomesBySource().get("a");
assertThat(a).isNotNull();
assertThat(a.isFullMatch()).isTrue();
}
@Test
void notFullMatch() {
prepareMatches(true, false, true);
assertThat(this.report.getConditionAndOutcomesBySource().get("a").isFullMatch()).isFalse();
ConditionAndOutcomes a = this.report.getConditionAndOutcomesBySource().get("a");
assertThat(a).isNotNull();
assertThat(a.isFullMatch()).isFalse();
}
private void prepareMatches(boolean m1, boolean m2, boolean m3) {
@ -203,9 +220,13 @@ class ConditionEvaluationReportTests {
Map<String, ConditionAndOutcomes> sourceOutcomes = report.getConditionAndOutcomesBySource();
assertThat(context.containsBean("negativeOuterPositiveInnerBean")).isFalse();
String negativeConfig = NegativeOuterConfig.class.getName();
assertThat(sourceOutcomes.get(negativeConfig).isFullMatch()).isFalse();
ConditionAndOutcomes negativeOutcome = sourceOutcomes.get(negativeConfig);
assertThat(negativeOutcome).isNotNull();
assertThat(negativeOutcome.isFullMatch()).isFalse();
String positiveConfig = NegativeOuterConfig.PositiveInnerConfig.class.getName();
assertThat(sourceOutcomes.get(positiveConfig).isFullMatch()).isFalse();
ConditionAndOutcomes positiveOutcome = sourceOutcomes.get(positiveConfig);
assertThat(positiveOutcome).isNotNull();
assertThat(positiveOutcome.isFullMatch()).isFalse();
}
@Test

View File

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.condition;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -42,7 +43,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*/
class ConditionalOnBooleanPropertyTests {
private ConfigurableApplicationContext context;
private @Nullable ConfigurableApplicationContext context;
private final ConfigurableEnvironment environment = new StandardEnvironment();
@ -56,97 +57,97 @@ class ConditionalOnBooleanPropertyTests {
@Test
void defaultsWhenTrue() {
load(Defaults.class, "test=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void defaultsWhenFalse() {
load(Defaults.class, "test=false");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void defaultsWhenMissing() {
load(Defaults.class);
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueTrueMatchIfMissingFalseWhenTrue() {
load(HavingValueTrueMatchIfMissingFalse.class, "test=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void havingValueTrueMatchIfMissingFalseWhenFalse() {
load(HavingValueTrueMatchIfMissingFalse.class, "test=false");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueTrueMatchIfMissingFalseWhenMissing() {
load(HavingValueTrueMatchIfMissingFalse.class);
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueTrueMatchIfMissingTrueWhenTrue() {
load(HavingValueTrueMatchIfMissingTrue.class, "test=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void havingValueTrueMatchIfMissingTrueWhenFalse() {
load(HavingValueTrueMatchIfMissingTrue.class, "test=false");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueTrueMatchIfMissingTrueWhenMissing() {
load(HavingValueTrueMatchIfMissingTrue.class);
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void havingValueFalseMatchIfMissingFalseWhenTrue() {
load(HavingValueFalseMatchIfMissingFalse.class, "test=true");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueFalseMatchIfMissingFalseWhenFalse() {
load(HavingValueFalseMatchIfMissingFalse.class, "test=false");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void havingValueFalseMatchIfMissingFalseWhenMissing() {
load(HavingValueFalseMatchIfMissingFalse.class);
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueFalseMatchIfMissingTrueWhenTrue() {
load(HavingValueFalseMatchIfMissingTrue.class, "test=true");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
}
@Test
void havingValueFalseMatchIfMissingTrueWhenFalse() {
load(HavingValueFalseMatchIfMissingTrue.class, "test=false");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void havingValueFalseMatchIfMissingTrueWhenMissing() {
load(HavingValueFalseMatchIfMissingTrue.class);
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
void withPrefix() {
load(HavingValueFalseMatchIfMissingTrue.class, "foo.test=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
}
@Test
@ -166,14 +167,14 @@ class ConditionalOnBooleanPropertyTests {
@Test
void conditionReportWhenMatched() {
load(Defaults.class, "test=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
assertThat(getConditionEvaluationReport()).contains("@ConditionalOnBooleanProperty (test=true) matched");
}
@Test
void conditionReportWhenDoesNotMatch() {
load(Defaults.class, "test=false");
assertThat(this.context.containsBean("foo")).isFalse();
assertThat(containsBean()).isFalse();
assertThat(getConditionEvaluationReport())
.contains("@ConditionalOnBooleanProperty (test=true) found different value in property 'test'");
}
@ -181,7 +182,7 @@ class ConditionalOnBooleanPropertyTests {
@Test
void repeatablePropertiesConditionReportWhenMatched() {
load(RepeatablePropertiesRequiredConfiguration.class, "property1=true", "property2=true");
assertThat(this.context.containsBean("foo")).isTrue();
assertThat(containsBean()).isTrue();
String report = getConditionEvaluationReport();
assertThat(report).contains("@ConditionalOnBooleanProperty (property1=true) matched");
assertThat(report).contains("@ConditionalOnBooleanProperty (property2=true) matched");
@ -199,6 +200,7 @@ class ConditionalOnBooleanPropertyTests {
}
private String getConditionEvaluationReport() {
assertThat(this.context).isNotNull();
return ConditionEvaluationReport.get(this.context.getBeanFactory())
.getConditionAndOutcomesBySource()
.values()
@ -215,6 +217,11 @@ class ConditionalOnBooleanPropertyTests {
.run();
}
private boolean containsBean() {
assertThat(this.context).isNotNull();
return this.context.containsBean("foo");
}
abstract static class BeanConfiguration {
@Bean

View File

@ -105,8 +105,10 @@ class ConditionalOnJavaTests {
FilteredClassLoader classLoader = new FilteredClassLoader(hiddenClasses);
Class<?> javaVersionClass = Class.forName(JavaVersion.class.getName(), false, classLoader);
Method getJavaVersionMethod = ReflectionUtils.findMethod(javaVersionClass, "getJavaVersion");
assertThat(getJavaVersionMethod).isNotNull();
Object javaVersion = ReflectionUtils.invokeMethod(getJavaVersionMethod, null);
classLoader.close();
assertThat(javaVersion).isNotNull();
return javaVersion.toString();
}

View File

@ -21,6 +21,7 @@ import java.util.Map;
import javax.naming.Context;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -29,6 +30,7 @@ import org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoad
import org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
@ -47,7 +49,7 @@ class ConditionalOnJndiTests {
private ClassLoader threadContextClassLoader;
private String initialContextFactory;
private @Nullable String initialContextFactory;
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@ -101,14 +103,16 @@ class ConditionalOnJndiTests {
@Test
void jndiLocationNotFound() {
ConditionOutcome outcome = this.condition.getMatchOutcome(null, mockMetadata("java:/a"));
ConditionOutcome outcome = this.condition.getMatchOutcome(mock(ConditionContext.class),
mockMetadata("java:/a"));
assertThat(outcome.isMatch()).isFalse();
}
@Test
void jndiLocationFound() {
this.condition.setFoundLocation("java:/b");
ConditionOutcome outcome = this.condition.getMatchOutcome(null, mockMetadata("java:/a", "java:/b"));
ConditionOutcome outcome = this.condition.getMatchOutcome(mock(ConditionContext.class),
mockMetadata("java:/a", "java:/b"));
assertThat(outcome.isMatch()).isTrue();
}
@ -151,7 +155,7 @@ class ConditionalOnJndiTests {
private final boolean jndiAvailable = true;
private String foundLocation;
private @Nullable String foundLocation;
@Override
protected boolean isJndiAvailable() {
@ -162,7 +166,7 @@ class ConditionalOnJndiTests {
protected JndiLocator getJndiLocator(String[] locations) {
return new JndiLocator(locations) {
@Override
public String lookupFirstLocation() {
public @Nullable String lookupFirstLocation() {
return MockableOnJndi.this.foundLocation;
}
};

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