Skip to content

Spring Boot 4 support #4268#153

Open
arey wants to merge 7 commits intolangchain4j:mainfrom
arey:feature/spring-boot-4
Open

Spring Boot 4 support #4268#153
arey wants to merge 7 commits intolangchain4j:mainfrom
arey:feature/spring-boot-4

Conversation

@arey
Copy link
Contributor

@arey arey commented Dec 23, 2025

Issue

Fixes langchain4j/langchain4j#4268 [BUG] Not compatible with Spring Boot 4.0

Change

This pull request updates dependencies and refactors code across several modules to ensure compatibility with Spring Boot 4. The most important changes are grouped below:

  • Spring Boot 4 upgrade and dependencies alignment (new spring boot starter artefact names)
  • SpringRestClient refactoring to use HttpClientSettings instead of the previous ClientHttpRequestFactorySettings
  • Updated test container dependencies across modules to use the new artifact names (e.g., testcontainers-junit-jupiter, testcontainers-elasticsearch, testcontainers-milvus)

General checklist

  • Build Success without unit test (mvn clean install -Dmaven.test.skip command line)
  • 3 SNAPSHOTS modules langchain4j-spring-boot-starter, langchain4j-open-ai-spring-boot-starterand langchain4j-http-client-spring-restclient tested on the Spring Boot 4 version of Spring Petclinic Langchain4j.
image
             |\      _,,,--,,_
             /,`.-'`'   ._  \-;;,_
  _______ __|,4-  ) )_   .;.(__`'-'__     ___ __    _ ___ _______
 |       | '---''(_/._)-'(_\_)   |   |   |   |  |  | |   |       |
 |    _  |    ___|_     _|       |   |   |   |   |_| |   |       | __ _ _
 |   |_| |   |___  |   | |       |   |   |   |       |   |       | \ \ \ \
 |    ___|    ___| |   | |      _|   |___|   |  _    |   |      _|  \ \ \ \
 |   |   |   |___  |   | |     |_|       |   | | |   |   |     |_    ) ) ) )
 |___|   |_______| |___| |_______|_______|___|_|  |__|___|_______|  / / / /
 ==================================================================/_/_/_/

:: Built with Spring Boot :: 4.0.2


2026-02-03T21:26:26.406+01:00  INFO 46056 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Starting PetClinicApplication using Java 21.0.5 with PID 46056 (/Users/arey/Dev/GitHub/spring-petclinic/spring-petclinic-langchain4j/target/classes started by arey in /Users/arey/Dev/GitHub/spring-petclinic/spring-petclinic-langchain4j)
2026-02-03T21:26:26.407+01:00 DEBUG 46056 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Running with Spring Boot v4.0.2, Spring v7.0.3
2026-02-03T21:26:26.407+01:00  INFO 46056 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : No active profile set, falling back to 1 default profile: "default"
2026-02-03T21:26:26.445+01:00  INFO 46056 --- [  restartedMain] o.s.b.devtools.restart.ChangeableUrls    : The Class-Path manifest attribute in /Users/arey/.m2/repository/org/apache/opennlp/opennlp-tools/2.5.4/opennlp-tools-2.5.4.jar referenced one or more files that do not exist: file:/Users/arey/.m2/repository/org/apache/opennlp/opennlp-tools/2.5.4/slf4j-api-2.0.17.jar
2026-02-03T21:26:26.445+01:00  INFO 46056 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2026-02-03T21:26:26.445+01:00  INFO 46056 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2026-02-03T21:26:26.824+01:00  INFO 46056 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2026-02-03T21:26:26.844+01:00  INFO 46056 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 16 ms. Found 3 JPA repository interfaces.
2026-02-03T21:26:26.913+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.spring.ClassPathAiServiceScanner   : Identified candidate component class: file [/Users/arey/Dev/GitHub/spring-petclinic/spring-petclinic-langchain4j/target/classes/org/springframework/samples/petclinic/chat/Assistant.class]
2026-02-03T21:26:27.166+01:00  INFO 46056 --- [  restartedMain] o.s.boot.tomcat.TomcatWebServer          : Tomcat initialized with port 8080 (http)
2026-02-03T21:26:27.172+01:00  INFO 46056 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2026-02-03T21:26:27.172+01:00  INFO 46056 --- [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/11.0.15]
2026-02-03T21:26:27.187+01:00  INFO 46056 --- [  restartedMain] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 742 ms
2026-02-03T21:26:27.259+01:00  INFO 46056 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2026-02-03T21:26:27.326+01:00  INFO 46056 --- [  restartedMain] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:84909555-8ad7-4a7b-b759-f418aecf39f1 user=SA
2026-02-03T21:26:27.327+01:00  INFO 46056 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2026-02-03T21:26:27.417+01:00  INFO 46056 --- [  restartedMain] org.hibernate.orm.jpa                    : HHH008540: Processing PersistenceUnitInfo [name: default]
2026-02-03T21:26:27.442+01:00  INFO 46056 --- [  restartedMain] org.hibernate.orm.core                   : HHH000001: Hibernate ORM core version 7.2.1.Final
2026-02-03T21:26:27.585+01:00  INFO 46056 --- [  restartedMain] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
2026-02-03T21:26:27.619+01:00  INFO 46056 --- [  restartedMain] org.hibernate.orm.connections.pooling    : HHH10001005: Database info:
	Database JDBC URL [jdbc:h2:mem:84909555-8ad7-4a7b-b759-f418aecf39f1]
	Database driver: H2 JDBC Driver
	Database dialect: H2Dialect
	Database version: 2.4.240
	Default catalog/schema: 84909555-8AD7-4A7B-B759-F418AECF39F1/PUBLIC
	Autocommit mode: undefined/unknown
	Isolation level: READ_COMMITTED [default READ_COMMITTED]
	JDBC fetch size: 100
	Pool: DataSourceConnectionProvider
	Minimum pool size: undefined/unknown
	Maximum pool size: undefined/unknown
2026-02-03T21:26:27.991+01:00  INFO 46056 --- [  restartedMain] org.hibernate.orm.core                   : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
2026-02-03T21:26:27.993+01:00  INFO 46056 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2026-02-03T21:26:33.685+01:00  INFO 46056 --- [  restartedMain] ai.djl.util.Platform                     : Found matching platform from: jar:file:/Users/arey/.m2/repository/ai/djl/huggingface/tokenizers/0.31.1/tokenizers-0.31.1.jar!/native/lib/tokenizers.properties
2026-02-03T21:26:33.889+01:00  INFO 46056 --- [  restartedMain] o.s.d.j.r.query.QueryEnhancerFactories   : Hibernate is in classpath; If applicable, HQL parser will be used.
2026-02-03T21:26:34.389+01:00  INFO 46056 --- [  restartedMain] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 13 endpoints beneath base path '/actuator'
2026-02-03T21:26:34.423+01:00  INFO 46056 --- [  restartedMain] o.s.boot.tomcat.TomcatWebServer          : Tomcat started on port 8080 (http) with context path '/'
2026-02-03T21:26:34.427+01:00  INFO 46056 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 8.194 seconds (process running for 8.553)
2026-02-03T21:26:34.585+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Starting to ingest 1 documents
2026-02-03T21:26:34.592+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Documents were split into 33 text segments
2026-02-03T21:26:34.592+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Starting to embed 33 text segments
2026-02-03T21:26:34.775+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Finished embedding 33 text segments
2026-02-03T21:26:34.775+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Starting to store 33 text segments into the embedding store
2026-02-03T21:26:34.775+01:00 DEBUG 46056 --- [  restartedMain] d.l.s.embedding.EmbeddingStoreIngestor   : Finished storing 33 text segments into the embedding store
2026-02-03T21:26:36.507+01:00  INFO 46056 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-02-03T21:26:36.507+01:00  INFO 46056 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2026-02-03T21:26:36.508+01:00  INFO 46056 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2026-02-03T21:26:54.478+01:00  INFO 46056 --- [pool-5-thread-1] d.l.http.client.log.LoggingHttpClient    : HTTP request:
- method: POST
- url: https://api.openai.com/v1/chat/completions
- headers: [Authorization: Beare...MA], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
  "model" : "gpt-4o-mini",
  "messages" : [ {
    "role" : "user",
    "content" : "Is the following query related to one or more veterinarians of the pet clinic?\nAnswer only 'yes' or 'no'.\nQuery: \"Please list the owners that come to the clinic.\"\n"
  } ],
  "stream" : false
}

2026-02-03T21:26:55.799+01:00  INFO 46056 --- [pool-5-thread-1] d.l.http.client.log.LoggingHttpClient    : HTTP response:
- status code: 200
- headers: [xxxx]
- body: {
  "id": "chatcmpl-D5HH5l1eX8wWXNgX551UTS6Y6teT6",
  "object": "chat.completion",
  "created": 1770150415,
  "model": "gpt-4o-mini-2024-07-18",
  "choices": [
 ...
  • There are breaking changes for Spring Boot 3 users => they have to upgrade to Spring Boot 4 or the Langchain4j team has to support both Spring Boot versions by releasing two versions of the same langchain4j-spring
  • No additional tests. The existing unit tests cover regression.
  • The tests cover both positive and negative cases
  • I have manually run all the unit and integration tests in the module I have added/changed, and they are all green
    On my laptop, integration tests are unstable. Sometimes they failed at the LangChain4j Spring Boot starter for OpenAI module, sometimes later. For instance:
[INFO] Reactor Summary for langchain4j-spring parent POM 1.11.0-beta19-SNAPSHOT:
[INFO] 
[INFO] langchain4j-spring parent POM ...................... SUCCESS [  1.831 s]
[INFO] LangChain4j :: HTTP Client :: Spring RestClient .... SUCCESS [02:40 min]
[INFO] LangChain4j Spring Boot starter for OpenAI ......... SUCCESS [ 36.428 s]
[INFO] Spring Boot starter for LangChain4j ................ SUCCESS [ 45.663 s]
[INFO] LangChain4j Spring Boot Tests ...................... SUCCESS [  0.563 s]
[INFO] LangChain4j Spring Boot starter for Anthropic ...... SUCCESS [  1.221 s]
[INFO] LangChain4j Spring Boot starter for Ollama ......... FAILURE [01:53 min]
[INFO] LangChain4j Spring Boot starter for Azure AI Search  SKIPPED

I've got 2 errors on the `LangChain4j Spring Boot starter for Ollama ` modules:
[ERROR]   AutoConfigIT.should_create_embedding_model_with_default_http_client:385 » ModelNotFound 404 Not Found: "404 page not found"
[ERROR]   AutoConfigIT.should_provide_embedding_model:367->lambda$should_provide_embedding_model$9:373 » ModelNotFound 404 Not Found: "404 page not found"
[INFO] 
[ERROR] Tests run: 12, Failures: 0, Errors: 2, Skipped: 0

The 404 error is being caused by the Ollama URL http://localhost:57369/api/embed

Checklist for adding new Spring Boot starter

N/A

@arey arey force-pushed the feature/spring-boot-4 branch from c4d7f3a to a44eeef Compare February 1, 2026 21:01
@arey arey marked this pull request as ready for review February 1, 2026 21:09
@arey arey force-pushed the feature/spring-boot-4 branch from a44eeef to 9d7a48f Compare February 1, 2026 21:12
@dliubarskyi
Copy link
Member

@arey please ping me by @dliubarskyi once this PR is ready (but no rush!)

…map instead of the asMultiValueMap deprecated method
@arey
Copy link
Contributor Author

arey commented Feb 3, 2026

@arey please ping me by @dliubarskyi once this PR is ready (but no rush!)

Hi @dliubarskyi, that sounds OK to me. I've added some comments to the main conversation. Other than the OPENAI_API_KEY, I don't have any other API tokens. Could you perhaps checkout my branch and execute all the integration tests?

@dliubarskyi
Copy link
Member

@arey

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for langchain4j-spring parent POM 1.11.0-beta19-SNAPSHOT:
[INFO] 
[INFO] langchain4j-spring parent POM ...................... SUCCESS [ 28.408 s]
[INFO] LangChain4j :: HTTP Client :: Spring RestClient .... SUCCESS [03:25 min]
[INFO] LangChain4j Spring Boot starter for OpenAI ......... SUCCESS [ 32.027 s]
[INFO] Spring Boot starter for LangChain4j ................ SUCCESS [ 40.327 s]
[INFO] LangChain4j Spring Boot Tests ...................... SUCCESS [  6.166 s]
[INFO] LangChain4j Spring Boot starter for Anthropic ...... SUCCESS [ 32.120 s]
[INFO] LangChain4j Spring Boot starter for Ollama ......... SUCCESS [ 14.465 s]
[INFO] LangChain4j Spring Boot starter for Azure AI Search  SUCCESS [ 19.252 s]
[INFO] LangChain4j Spring Boot starter for Azure OpenAI ... SUCCESS [ 26.874 s]
[INFO] LangChain4j Spring Boot starter for Voyage AI ...... SUCCESS [ 10.037 s]
[INFO] LangChain4j Spring Boot starter for GitHub Models .. SUCCESS [ 12.668 s]
[INFO] LangChain4j Spring Boot starter for Google AI Gemini SUCCESS [ 12.004 s]
[INFO] LangChain4j Spring Boot starter for Vertex AI Gemini SUCCESS [ 12.766 s]
[INFO] LangChain4j Spring Boot starter for Elasticsearch .. FAILURE [ 56.101 s]
[INFO] LangChain4j Spring Boot starter for Milvus ......... SUCCESS [ 29.385 s]
[INFO] LangChain4j Spring Boot starter for MistralAI ...... SUCCESS [ 13.379 s]
[INFO] LangChain4j integration with Project Reactor ....... SUCCESS [  4.169 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  05:08 min (Wall Clock)
[INFO] Finished at: 2026-02-04T10:03:45+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-failsafe-plugin:3.5.4:verify (default) on project langchain4j-elasticsearch-spring-boot-starter: 
[ERROR] 
[ERROR] See C:\dev\repo\langchain4j-spring\langchain4j-elasticsearch-spring-boot-starter\target\failsafe-reports for the individual test results.
[ERROR] See dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
10:05:14.949 [main] INFO dev.langchain4j.store.embedding.elasticsearch.spring.ElasticsearchTestContainerHelper -- Starting testcontainers with Elasticsearch [8.19.2].
10:05:14.983 [main] INFO org.testcontainers.images.PullPolicy -- Image pull policy will be performed by: DefaultPullPolicy()
10:05:14.985 [main] INFO org.testcontainers.utility.ImageNameSubstitutor -- Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
10:05:15.041 [main] INFO org.testcontainers.DockerClientFactory -- Testcontainers version: 2.0.3
10:05:15.219 [main] INFO org.testcontainers.dockerclient.DockerClientProviderStrategy -- Loaded org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
10:05:15.680 [main] INFO org.testcontainers.dockerclient.DockerClientProviderStrategy -- Found Docker environment with local Npipe socket (npipe:////./pipe/docker_engine)
10:05:15.681 [main] INFO org.testcontainers.DockerClientFactory -- Docker host IP address is localhost
10:05:15.729 [main] INFO org.testcontainers.DockerClientFactory -- Connected to docker: 
  Server Version: 5.2.3
  API Version: 1.41
  Operating System: fedora
  Total Memory: 15836 MB
10:05:15.886 [main] INFO tc.testcontainers/ryuk:0.13.0 -- Creating container for image: testcontainers/ryuk:0.13.0
10:05:15.892 [main] INFO org.testcontainers.utility.RegistryAuthLocator -- Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: testcontainers/ryuk:0.13.0, configFile: C:\Users\ljuba\.docker\config.json, configEnv: DOCKER_AUTH_CONFIG). Falling back to docker-java default behaviour. Exception message: Status 404: No config supplied. Checked in order: C:\Users\ljuba\.docker\config.json (file not found), DOCKER_AUTH_CONFIG (not set)
10:05:16.008 [main] INFO tc.testcontainers/ryuk:0.13.0 -- Container testcontainers/ryuk:0.13.0 is starting: aea86a04ae9c8b1a0b1f74567637f711f968e41f0c413cf29f91c710722cac1a
10:05:16.409 [main] INFO tc.testcontainers/ryuk:0.13.0 -- Container testcontainers/ryuk:0.13.0 started in PT0.5227434S
10:05:16.412 [main] INFO org.testcontainers.utility.RyukResourceReaper -- Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
10:05:16.412 [main] INFO org.testcontainers.DockerClientFactory -- Checking the system...
10:05:16.412 [main] INFO org.testcontainers.DockerClientFactory -- ✔︎ Docker server version should be at least 1.6.0
10:05:16.413 [main] INFO tc.docker.elastic.co/elasticsearch/elasticsearch:8.19.2 -- Creating container for image: docker.elastic.co/elasticsearch/elasticsearch:8.19.2
10:05:16.413 [main] INFO org.testcontainers.utility.RegistryAuthLocator -- Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: docker.elastic.co/elasticsearch/elasticsearch:8.19.2, configFile: C:\Users\ljuba\.docker\config.json, configEnv: DOCKER_AUTH_CONFIG). Falling back to docker-java default behaviour. Exception message: Status 404: No config supplied. Checked in order: C:\Users\ljuba\.docker\config.json (file not found), DOCKER_AUTH_CONFIG (not set)
10:05:16.562 [main] INFO tc.docker.elastic.co/elasticsearch/elasticsearch:8.19.2 -- Container docker.elastic.co/elasticsearch/elasticsearch:8.19.2 is starting: 3f1c41c57a91d7e399e78bde78d0482cd5eaa1840347b19e06a1c5abd5975d41
10:05:45.265 [main] INFO tc.docker.elastic.co/elasticsearch/elasticsearch:8.19.2 -- Container docker.elastic.co/elasticsearch/elasticsearch:8.19.2 started in PT28.8517752S

Test ignored.

Test ignored.

co.elastic.clients.elasticsearch._types.ElasticsearchException: [es/info] failed: [media_type_header_exception] Invalid media-type value on headers [Accept, Content-Type]

	at co.elastic.clients.transport.ElasticsearchTransportBase.getApiResponse(ElasticsearchTransportBase.java:372)
	at co.elastic.clients.transport.ElasticsearchTransportBase.performRequest(ElasticsearchTransportBase.java:154)
	at co.elastic.clients.elasticsearch.ElasticsearchClient.info(ElasticsearchClient.java:3376)
	at dev.langchain4j.store.embedding.elasticsearch.spring.ElasticsearchTestContainerHelper.getClient(ElasticsearchTestContainerHelper.java:94)
	at dev.langchain4j.store.embedding.elasticsearch.spring.ElasticsearchTestContainerHelper.startServices(ElasticsearchTestContainerHelper.java:65)
	at dev.langchain4j.store.embedding.elasticsearch.spring.ElasticsearchEmbeddingStoreAutoConfigurationIT.startServices(ElasticsearchEmbeddingStoreAutoConfigurationIT.java:27)


Process finished with exit code -1

@dliubarskyi
Copy link
Member

I am wondering if we should migrate straight to 4 (as is done in this PR), or support both 3 and 4 in parallel for some time. WDYT?

@arey
Copy link
Contributor Author

arey commented Feb 7, 2026

@dliubarskyi I fixed the Elasticsearch issue by sticking with version 8.19.2.

[INFO] Reactor Summary for LangChain4j Spring Boot starter for Elasticsearch 1.11.0-beta19-SNAPSHOT:
[INFO] 
[INFO] LangChain4j Spring Boot starter for Elasticsearch .. SUCCESS [ 19.954 s]
[INFO] LangChain4j Spring Boot starter for Milvus ......... SUCCESS [ 15.311 s]
[INFO] LangChain4j Spring Boot starter for MistralAI ...... SUCCESS [  2.834 s]
[INFO] LangChain4j integration with Project Reactor ....... SUCCESS [  1.004 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

I don't know how, within the Langchain project, you support different versions of technologies that are not upward compatible, such as Spring Boot 4 against Spring Boot 3.

In general, I think most developers are using the latest stack for their GenAI project. Therefore, it could be acceptable to only keep the most recent version of Spring Boot.

Of course, it would be better to support both major versions of Spring Boot. I think it's technically possible to do this using reflection on the SpringRestClient class. In the two other changed AutoConfig classes where an import has changed, maybe we could try something like that:

@AutoConfiguration(afterName =
        {"org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration", // Spring Boot 4
        "org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration"} // Spring Boot 3
)

@dliubarskyi
Copy link
Member

@arey I was thinking more of a duplicated set of modules for Spring Boot 4, but if reflection approach works, why not

@arey
Copy link
Contributor Author

arey commented Feb 8, 2026

@dliubarskyi my last commit 833ac80 provides an overview of how to use reflection to support both versions of Spring Boot without duplicating modules (see the SpringBoot3HttpClientSettingsclass).

We use a strategy pattern. Of course, the code is much more complex to maintain. But in a few months/years, we could revert this commit in order to remove support for Spring Boot 3.x

No unit tests have been written for the SpringBoot3HttpClientSettings class. However, I manually tested it by copying and pasting code into the Spring Boot 3.5 version of the langchain4j-spring project (main branch).

Another approach could be to move the SpringBoot3HttpClientSettings class into a legacy langchain4j-http-client-spring-restclient-sb3(something like taht) module, which would depend on Spring Boot 3. This would allow us to remove all the reflection code.

@danielschweiger1
Copy link

danielschweiger1 commented Feb 9, 2026

Hello any update when the Spring boot 4 upgrade is probably going to be released on maven central?
it blocks our project software update to Spring boot 4 as the langchain4j-spring is not working anymore with v4.
Thank you

@arey arey changed the title Spring Boot 4 support #4268 (work in progress) Spring Boot 4 support #4268 Feb 10, 2026
@arey
Copy link
Contributor Author

arey commented Feb 22, 2026

Hi @dliubarskyi, did you see my latest commit? Would you like to merge it as it is, or would you prefer to have a code without introspection in a new Maven module?

@dliubarskyi
Copy link
Member

@arey I just tested your latest changes with Spring Boot 3.4.2 app and it fails to start:

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'restClientSsl', defined in class path resource [org/springframework/boot/restclient/autoconfigure/RestClientAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

I am not sure this approach is reliable, I would probably go with a separate set of module(s) for SB4, WDYT?

@dliubarskyi
Copy link
Member

I mean keeping existing modules for SB 3 and introduce new modules for SB 4

Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
@arey
Copy link
Contributor Author

arey commented Mar 4, 2026

@dliubarskyi I see where the problem you're encountering comes from. The RestClientAutoConfiguration class has been relocated to a new package in Spring Boot 4 (org.springframework.boot.autoconfigure.web.client to org.springframework.boot.restclient.autoconfigure).
When an SB 3 application pulls one of the langchain4j-spring starters, it transitively pulls the spring-boot-starter-restclient JAR from SB4. The mix of Spring Boot 4 / Spring Framework 7 vs Spring Boot 3 / Spring Framework 6 artifacts causes the build or application startup to fail.

I tried to stop loading the Spring Boot starters again to remove as many auto-configuration classes as possible, but it didn't work

i.e., java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/PropertyMapper$Source$Adapter

Rather than duplicating the 18 modules of the langchain4j-spring project, I wonder if we shouldn't maintain a springboot3 branch dedicated to Spring Boot 3 backward compatibility.
We would then need to transfer (and sometimes adapt to the SB3 APIs) the changes from the main branch to springboot3.

WDYT?

@dliubarskyi
Copy link
Member

@arey we certainly need to maintain SB3 compatibility, these modules have lots of users at the moment, we can't just break it for them. If we want to support SB4, we either need to release a next major version of LC4j (e.g., 2.X), or have a separate set of dependencies released specifically for SB4. Since 2.X is still far away, I would go with a separate set of modules.

Introducing separate branch would also work, but it would complicate the release process because we would need to change it to release from both branches.

import java.time.Duration;

/**
* The Spring Boot 3.5+ implementation uses reflection because Spring Boot 4 is no longer included in the langchain4J-spring classpath.
Copy link
Collaborator

@ThomasVitale ThomasVitale Mar 5, 2026

Choose a reason for hiding this comment

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

Spring Boot 3.5 will reach end of life in June and projects are encouraged to upgrade (see Support page). I would suggest considering if it's desireable to maintain 3.5 support here, even if not supported upstream. If it is, I would recommend considering publishing separate modules, as it's quite risky and complex to support both major version in the same artifact.

Copy link
Member

Choose a reason for hiding this comment

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

Considering that I see a lot of usage of LC4j-SB modules (and given that they support only 3.x), and it is growing, I think it is worth maintaining it untill we see a considerable drop in usage of these modules.

Also, as far as I see, enterprise support of 3.5.x is planned untill 2032.

Copy link
Contributor Author

@arey arey Mar 7, 2026

Choose a reason for hiding this comment

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

@ThomasVitale @dliubarskyi
I think I might have found a solution to avoid duplicated all the Maven modules. I've tested it with langchain4j-openai-springboot-starter on https://github.com/spring-petclinic/spring-petclinic-langchain4j, which still uses Spring Boot 3.4.

My idea is to exclude all the Spring artefacts and allow the application client to decide which Spring Boot version to use. To do that, we could use the Maven <scope>provided</scope>
Exemple: pom-langchain4j-open-ai-spring-boot-starter.xml

Maven dependency tree on Langchain4j starter side:
dependency-tree-langchain4j-open-ai-spring-boot-starter.log

Maven dependency tree on the Spring Petclinic side:
dependency-tree-petclinic.log

Spring Petclinic startup log:

2026-03-07T11:04:28.725+01:00 DEBUG 13176 --- [           main] c.s.r.SpringBootHttpClientSettingsHelper : Detected Spring Boot major version 3

See complete logs: petclinic-logs.log

Existing Spring Boot 3.x applications should not be impacted because the ClientHttpRequestFactorySettings class belongs to the main spring-boot-3.x.jar.

Future Spring Boot 4 applications may have to add the spring-boot-http-client dependency (or spring-boot-restclient) in addition to the langchain4j-open-ai-spring-boot-starter dependency.

@dliubarskyi if you want to test, I could a go ahead and prepare a commit with the described solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dliubarskyi @ThomasVitale I have another idea for avoiding the duplication of all the Maven modules.
We could use two Maven profiles to build the project: sb3 and sb4.
Each profile contains a property with the Spring Boot version.
By default, we could target Spring Boot 4 (the sb4 profile). However, GitHub Actions could also build the project against the sb3 profile. We will have to run two Maven releases. Once for each profile.

If we take this approach, we must decide about a naming convention on the artefactId or the Maven version (or another proposal).
In the parent pom.xml:

<profile>
    <id>sb3</id>
    <properties>
        <langchain4j-spring-prefix>sb3</langchain4j-spring-prefix>
        <spring.boot.version>3.5.9</spring.boot.version>
    </properties>
</profile>

At the top of the Open AI Spring boot starter :

<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<name>LangChain4j Spring Boot starter for OpenAI</name>
<version>1.12.0-beta20-${langchain4j-spring-prefix}-SNAPSHOT</version>

or

<artifactId>langchain4j-open-ai-spring-boot-starter-${langchain4j-spring-prefix}</artifactId>
<name>LangChain4j Spring Boot starter for OpenAI</name>
<version>1.12.0-beta20-SNAPSHOT</version>

To avoid git tag conflict during the maven release, the first option is maybe the better.

With this second solution, I suppose we could have only 2 duplicated modules for the langchain4j-http-client-spring-restclient artefact, each for one major version of Spring Boot. No more introspection code.

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.

[BUG] Not compatible with Spring Boot 4.0

4 participants