spring-projects / spring-projects/spring-ai
Align spring-ai-openai on OkHttp 5.x (okhttp-jvm) to avoid silent duplicate classes with Spring Boot 4's OpenTelemetry starter (Maven)
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
Expected Behavior
spring-ai-openai should depend on the OkHttp 5.x line via the Maven-visible okhttp-jvm artifact — the same choice OpenTelemetry Java made in opentelemetry-exporter-sender-okhttp — so that Maven projects combining Spring AI with OkHttp-5-based libraries resolve exactly one copy of the okhttp3.* classes:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-jvm</artifactId>
<version>5.3.2</version>
</dependency>
Note: depending on the root okhttp:5.x artifact instead would not work for Maven consumers. Since OkHttp 5's Kotlin-multiplatform split, the root jar is an empty redirect stub (3 metadata files, no classes) and its POM does not reference okhttp-jvm — the redirect exists only in Gradle module metadata, which Maven ignores.
Current Behavior
spring-ai-openai:2.0.0 declares com.squareup.okhttp3:okhttp:4.12.0 (compile scope). Spring Boot 4's spring-boot-starter-opentelemetry — the default observability path — brings okhttp-jvm:5.3.2 through the OTLP sender. With spring-boot-starter-parent:4.1.0, these two starters alone reproduce:
+- org.springframework.boot:spring-boot-starter-opentelemetry:jar:4.1.0:compile
| \- io.opentelemetry:opentelemetry-exporter-otlp:jar:1.62.0:runtime
| \- io.opentelemetry:opentelemetry-exporter-sender-okhttp:jar:1.62.0:runtime
| \- com.squareup.okhttp3:okhttp-jvm:jar:5.3.2:runtime
\- org.springframework.ai:spring-ai-starter-model-openai:jar:2.0.0:compile
\- org.springframework.ai:spring-ai-openai:jar:2.0.0:compile
\- com.squareup.okhttp3:okhttp:jar:4.12.0:compile
Because the artifactIds differ, Maven's version mediation never sees a conflict: both jars land on the runtime classpath with 253 class files duplicated between them (essentially all of okhttp3.*). Maven and Boot's repackaging emit no warning — Gradle fails loudly on this exact artifact pair (see open-telemetry/opentelemetry-android#1294).
Which bytecode actually runs is then decided by classpath order. In our Boot fat jar, okhttp-jvm-5.3.2.jar precedes okhttp-4.12.0.jar, so the OpenAI client already runs on OkHttp 5 classes today — silently, and dependent on nothing more than dependency declaration order. Mixed 4.x/5.x-jvm classpaths are known to produce hard failures such as NoSuchMethodError when the order or API surface shifts (e.g. aws/aws-sdk-kotlin#983).
This can't be cleanly fixed from the consumer side: mediation can't converge two artifactIds, Spring Boot no longer manages OkHttp versions at all (spring-projects/spring-boot#36632), and pinning root okhttp to 5.x just resolves to the empty stub jar described above.
Context
- Spring AI 2.0.0, Spring Boot 4.1.0, Java 25, Maven 3.9.9.
- We combine
spring-ai-starter-model-openaiandspring-ai-starter-mcp-server-webmvcwithspring-boot-starter-opentelemetry. Since the OTel starter is Boot 4's standard observability setup, we expect this pairing to be common among Maven-based Spring AI applications. - Impact on us: our dependency-hygiene tooling flags the 253 shadowed classes, and the OpenAI client effectively runs on an OkHttp version other than the one Spring AI declares and presumably tests against.
- Workaround we applied — exclude the 4.x jar and let the client run on
okhttp-jvm:5.3.2(which classpath order was already doing; OkHttp 5 retains the 4.x public API, and the client works unmodified):
<exclusion>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
This is fragile: the OpenAI client's HTTP classes now arrive only via the OTel starter's runtime dependency, so removing that starter would cause NoClassDefFoundError.
- Alternative considered: swapping the OTLP sender to
opentelemetry-exporter-sender-jdk, which removes OkHttp 5 but changes the telemetry transport and keeps Spring AI on the maintenance-only 4.x line. - Related issues (searched first): #5838 proposes replacing OkHttp with JDK HttpClient in the OpenAI SDK integration, which would resolve this more fundamentally — this request is the narrower dependency alignment until/unless that lands. #6318 and #354 show OkHttp on the client's hot path.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the Maven dependency declaration for the spring-ai-openai artifact and compare it with the okhttp-jvm dependency used by opentelemetry-exporter-sender-okhttp. Verify the published dependency tree with the Spring Boot OpenTelemetry combination; done means the OpenAI integration resolves okhttp-jvm without also bringing the root okhttp 4.12.0 artifact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100