Skip to content

Conversation

@bedrin
Copy link

@bedrin bedrin commented Oct 31, 2025

This PR adds compatibility with Spring Framework 7 to enable early adoption

  • Use only Spring Framework APIs available both in 6.x and 7.x branches
  • Add constructors without logic to *Api classes in models modules to simplify extensibility; effective final fields are marked as final
  • Kotlin 2.x support; use kotlin compiler version 2.2.21
  • Update MCP SDK to 0.15.0
  • Update MCP Annotations to 0.6.0

NOTE: this PR doesn't add support of Spring Boot 4 - it requires a separate and much bigger change and will be carried over in separate PR. This PR doesn't break existing Spring Boot 3.5 / Spring Framework 6 compatibility and can be merged into Spring AI 1.1.x release

- Use only Spring Framework APIs available both in 6.x and 7.x branches
- Add constructors without logic to ``*Api` classes in `models` modules to simplify extensibility; effective final fields are marked as final
- Kotlin 2.x support; use kotlin compiler version 2.2.21
- Update MCP SDK to 0.15.0
- Update MCP Annotations to 0.6.0

Signed-off-by: Dmitry Bedrin <dmitry.bedrin@gmail.com>
bedrin added a commit to OncoSteps/spring-ai that referenced this pull request Oct 31, 2025
- Updated Spring Boot dependency to 4.0.0.RC1
- Spring Framework 7 API compatibility (see below)
- Migration to Spring Boot 4.x as per https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide :
  * Adopt new modular design of starters
  * Use new Jackson 3.x API
  * Support Property Mapper API changes around null handling
- Updated Swagger codegen templates used by huggingface model to align with latest Spring Framework APIs
- Update elasticsearch test container to 9.2.0
- Added `FailureDetectingExternalResource` from old versions of `testcontainers` library to support `gemfire-testcontainers`
- Other related dependencies updates:
  * Spring Retry to 2.0.12
  * TestContainers to 2.0.1
  * GemFire testcontainers to 2.3.3
  * opensearch-testcontainers to 4.0.0
  * Rest Assured to 5.5.6
  * swagger-codegen-maven-plugin to 3.0.75

Fixes spring-projectsGH-3379 (spring-projects#3379)

Built on-top of spring-projects#4771
- Use only Spring Framework APIs available both in 6.x and 7.x branches
- Add constructors without logic to `*Api` classes in `models` modules to simplify extensibility; effective final fields are marked as final
- Kotlin 2.x support; use kotlin compiler version 2.2.21
- Update MCP SDK to 0.15.0
- Update MCP Annotations to 0.6.0

Future tasks:
- Raise issue to migrate from Spring Retry to Spring Framework 7 built-in retry functionality
- Raise issue with `swagger-codegen-maven-plugin` to support Spring Framework 7
- Raise issue with GemFire to support testcontainers 2.x

Signed-off-by: Dmitry Bedrin <dmitry.bedrin@gmail.com>
bedrin added a commit to OncoSteps/spring-ai that referenced this pull request Oct 31, 2025
- Updated Spring Boot dependency to 4.0.0.RC1
- Spring Framework 7 API compatibility (see below)
- Migration to Spring Boot 4.x as per https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide :
  * Adopt new modular design of starters
  * Use new Jackson 3.x API
  * Support Property Mapper API changes around null handling
  * Migrated from Spring Retry to Spring Framework Retry functionality
- Updated Swagger codegen templates used by huggingface model to align with latest Spring Framework APIs
- Update elasticsearch test container to 9.2.0
- Added `FailureDetectingExternalResource` from old versions of `testcontainers` library to support `gemfire-testcontainers`
- Other related dependencies updates:
  * TestContainers to 2.0.1
  * GemFire testcontainers to 2.3.3
  * opensearch-testcontainers to 4.0.0
  * Rest Assured to 5.5.6
  * swagger-codegen-maven-plugin to 3.0.75

Fixes spring-projectsGH-3379 (spring-projects#3379)

Includes changes by @paulbakker from spring-projects#4681

Built on-top of spring-projects#4771
- Use only Spring Framework APIs available both in 6.x and 7.x branches
- Add constructors without logic to `*Api` classes in `models` modules to simplify extensibility; effective final fields are marked as final
- Kotlin 2.x support; use kotlin compiler version 2.2.21
- Update MCP SDK to 0.15.0
- Update MCP Annotations to 0.6.0

Future tasks:
- [x] Raise issue to migrate from Spring Retry to Spring Framework 7 built-in retry functionality: spring-projects#4681
- [ ] Raise issue with `swagger-codegen-maven-plugin` to support Spring Framework 7
- [x] Raise issue with GemFire to support testcontainers 2.x: gemfire/gemfire-testcontainers#7

Signed-off-by: Dmitry Bedrin <dmitry.bedrin@gmail.com>
@ilayaperumalg ilayaperumalg added this to the 2.0.0.M1 milestone Nov 4, 2025
@bedrin bedrin force-pushed the feature/spring-framework-7-support branch 2 times, most recently from 82590ca to 6457787 Compare November 6, 2025 15:45
@bedrin
Copy link
Author

bedrin commented Nov 7, 2025

Merged main into this branch - ready for review. This feature brings compatibility with Spring Framework 7.x while keeping it compatible with existing versions (It does NOT support Sprig Boot 4 though). @ilayaperumalg do you think we can merge it to 1.1.x instead? The goal is to allow early adoption and early feedback without having to wait for 2.0 release. In my project I'm not using Spring Boot part of Spring AI so we can already benefit from it.

Copy link
Contributor

@filiphr filiphr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ericbottard for pointing me to this PR. It is indeed a bit more complete that mine at #4817. However, I believe that some of the things I did in my PR are a bit more performant. e.g. the use of HttpHeaders.readOnlyHttpHeaders is less optimal than the one I am using

additionalHttpHeader.forEach(headers::addAll);

I've left some comments inline.

Additionally, I believe that this PR will still not make the entire codebase compile against Spring 7 and that's because of the HuggingFace generated ApiClient using removed methods in Spring 7. If the ApiClient.mustache from my PR is added then this would be complete.

Additionally, I also added a GitHub action (https://github.com/spring-projects/spring-ai/pull/4817/files#diff-e76e5134b85a9eb3e0d9ce8e671ce97c8c577ff3c24162c45d71691078201347) which compiles the project against Spring 7, so if you want to make sure that Spring AI 1.x stays compatible with Spring 7 I would advise adding that as well.

.uri(this.completionsPath)
.headers(headers -> {
headers.addAll(additionalHttpHeader);
headers.addAll(HttpHeaders.readOnlyHttpHeaders(additionalHttpHeader));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works however it is less performant as it keeps creating new objects even when additionalHttpHeader is empty. I would advise something more like:

additionalHttpHeader.forEach(headers::addAll);

private static Duration getHeaderAsDuration(ResponseEntity<?> response, String headerName) {
var headers = response.getHeaders();
if (headers.containsKey(headerName)) {
if (null != headers.getFirst(headerName)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be optimized a bit since at the moment the headers are fetched twice. The getFirst is not needed. The entire section could be

var values = headers.get(headerName);
if (!CollectionUtils.isEmpty(values)) {
    return DurationFormatter.TIME_UNIT.parse(values.get(0));
}

or

var value = headers.getFirst(headerName);
if (value != null) {
    return DurationFormatter.TIME_UNIT.parse(value);
}

private static Long getHeaderAsLong(ResponseEntity<?> response, String headerName) {
var headers = response.getHeaders();
if (headers.containsKey(headerName)) {
if (null != headers.getFirst(headerName)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as for getHeaderAsDuration

<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
<kotlin.compiler.version>2.2.21</kotlin.compiler.version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a Kotlin expert, but what does it mean if you use Kotlin compiler 2.2.21? When I tried to compile the project using Kotlin version 1.9.25 it was complaining because Spring Framework 7 had classes that were compiled with 2.2. It could mean that users would have the same problem if they want to use Spring AI 1.x with Spring 6.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch!

@bedrin
Copy link
Author

bedrin commented Nov 7, 2025

Thanks @ericbottard for pointing me to this PR. It is indeed a bit more complete that mine at #4817. However, I believe that some of the things I did in my PR are a bit more performant. e.g. the use of HttpHeaders.readOnlyHttpHeaders is less optimal than the one I am using

additionalHttpHeader.forEach(headers::addAll);

I've left some comments inline.

It's already done in PR for Spring Boot 4 support:
https://github.com/spring-projects/spring-ai/pull/4774/files#diff-e5cb77ca54425cc7c57b08f1d70da4118eaf2c0377d381b1d184ace96d6f6e89R417

This PR for Spring Framework 7 support might have some tradeoffs to keep everything compatible with both Spring Framework 6 and 7 but I don't think it makes any noticeable difference.

Additionally, I believe that this PR will still not make the entire codebase compile against Spring 7 and that's because of the HuggingFace generated ApiClient using removed methods in Spring 7. If the ApiClient.mustache from my PR is added then this would be complete.

I did it in separate PR for Spring Boot 4 support but I agree it should be part of Spring 7 support:
https://github.com/spring-projects/spring-ai/pull/4774/files?file-filters%5B%5D=.mustache&show-viewed-files=true#diff-111a294df116430873f6cc4f6fc2e14f67369bb65bd706c65b778cf41ac3ca2c

Additionally, I also added a GitHub action (https://github.com/spring-projects/spring-ai/pull/4817/files#diff-e76e5134b85a9eb3e0d9ce8e671ce97c8c577ff3c24162c45d71691078201347) which compiles the project against Spring 7, so if you want to make sure that Spring AI 1.x stays compatible with Spring 7 I would advise adding that as well.

Need input from maintainers here if it makes sense to have it or keep it simple before 2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants