[Bug] dubbo-rest-spring is incompatible with Spring Framework 6+ due to a javax/jakarta Servlet API mismatch
- Dominant language
- Java
- Stars
- 41.6k
- Forks
- 26.4k
- Avg merge
- 15h 13m
- Merged PRs (30d)
- 4
Description
### Pre-check
- [x] I am sure that all the content I provide is in English.
### Search before asking
- [x] I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar issues.
### Apache Dubbo Component
Java SDK (apache/dubbo)
### Dubbo Version
Apache Dubbo: 3.3 branch
Verified commit: d0bf5c36d092da8067b15a1d1d00884a8c399e8e
Project version: 3.3.7-SNAPSHOT
JDK: OpenJDK 17.0.19
Spring Framework: 6.2.18
Operating system: Ubuntu 24.04
### Steps to reproduce this issue
The `dubbo-rest-spring` module still uses `javax.servlet` types, while the corresponding Spring Framework 6 APIs use `jakarta.servlet` types.
The problem can be reproduced independently at both the source-compilation stage and the published-artifact consumption stage.
### 1. Mini reproduction using the published artifacts
Download the attached reproduction:
[dubbo-rest-spring-actual-repro.zip](https://github.com/user-attachments/files/30163504/dubbo-rest-spring-actual-repro.zip)
This reproduction uses the actual Maven Central artifacts rather than locally reimplemented adapters:
```text
org.apache.dubbo:dubbo-rest-spring:3.3.6
org.apache.dubbo:dubbo-triple-servlet:3.3.6
Spring Framework 5.3.39 and 6.2.18
```
Run it with:
```bash
unzip dubbo-rest-spring-actual-repro.zip
cd dubbo-rest-spring-actual-repro
./run-reproduction.sh
```
The script downloads the exact artifacts from Maven Central, verifies their published SHA-1 values, and performs six checks:
1. It extracts the real `HandlerInterceptorAdapter.java` and `SpringMiscArgumentResolver.java` from the published `dubbo-rest-spring:3.3.6` sources jar.
2. The extracted sources compile successfully against Spring Framework 5.3.39.
3. The same sources fail against Spring Framework 6.2.18 at the four reported locations:
* `HandlerInterceptorAdapter.java:71`
* `HandlerInterceptorAdapter.java:85`
* `HandlerInterceptorAdapter.java:92`
* `SpringMiscArgumentResolver.java:58`
4. A Spring Framework 6 consumer of the published `dubbo-rest-spring` binary compiles successfully.
5. Passing Dubbo's real Jakarta `ServletHttpRequestAdapter` to the real `HandlerInterceptorAdapter` fails at line 71 because the adapter casts it to `javax.servlet.http.HttpServletRequest`.
6. Passing Dubbo's real javax request implementation reaches the Spring API boundary and produces the expected linkage failures:
```text
java.lang.NoSuchMethodError:
HandlerInterceptor.preHandle(
javax.servlet.http.HttpServletRequest,
javax.servlet.http.HttpServletResponse,
java.lang.Object)
at HandlerInterceptorAdapter.java:71
```
and:
```text
java.lang.NoSuchMethodError:
ServletWebRequest.(
javax.servlet.http.HttpServletRequest)
at SpringMiscArgumentResolver.java:58
```
The runtime output also verifies that the affected classes were loaded from `dubbo-rest-spring-3.3.6.jar` and that the request implementations were loaded from `dubbo-triple-servlet-3.3.6.jar`.
Both Servlet APIs are deliberately present in the demo so that it can distinguish the cast failure from the deeper Spring method-descriptor incompatibility. On a Jakarta-only Spring Boot 3 classpath, the same integration may fail earlier with a missing-class error.
### 2. Repository reactor reproduction
From the Dubbo repository root at commit d0bf5c36d092da8067b15a1d1d00884a8c399e8e, run:
```bash
./mvnw -P spring-6 \
-pl dubbo-plugin/dubbo-rest-spring \
-am \
-Dspring-6.version=6.2.18 \
-Dmaven.test.skip=true \
-Dcheckstyle.skip=true \
-Drat.skip=true \
install
```
Tests and selected quality checks are skipped only to isolate main-source compilation. This does not bypass or hide the reported failure.
The command selects 54 reactor modules:
* the first 53 modules succeed;
* `dubbo-rest-spring [54/54]` fails while compiling its main sources;
* the final result is `BUILD FAILURE`.
The relevant compilation errors are:
```text
HandlerInterceptorAdapter.java:[71,27] cannot access HttpServletRequest
class file for jakarta.servlet.http.HttpServletRequest not found
HandlerInterceptorAdapter.java:[85,35] incompatible types:
javax.servlet.http.HttpServletRequest cannot be converted to
jakarta.servlet.http.HttpServletRequest
HandlerInterceptorAdapter.java:[92,40] incompatible types:
javax.servlet.http.HttpServletRequest cannot be converted to
jakarta.servlet.http.HttpServletRequest
SpringMiscArgumentResolver.java:[58,41] incompatible types:
javax.servlet.http.HttpServletRequest cannot be converted to
jakarta.servlet.http.HttpServletRequest
```
All four source locations are reproducible.
Because the attached mini reproduction deliberately provides both Servlet API jars, its Spring Framework 6 compilation reports line 71 as another explicit `javax.servlet` to `jakarta.servlet` incompatible-types error instead of a missing `jakarta.servlet` class. The underlying incompatibility is the same.
### What you expected to happen
The module set selected by the existing `spring-6` profile should be compilable against Spring Framework 6.
The `dubbo-rest-spring` integration should either provide a Spring Framework 6 compatible implementation using the Jakarta Servlet API, or clearly exclude this integration from the Spring Framework 6 compatibility scope with the limitation documented explicitly.
The existing Spring Framework 5 / `javax.servlet` behavior and artifact compatibility should remain unchanged.
### Anything else
## Discovery context
I found this issue while validating Apache Dubbo compatibility with Spring Boot 4 and its Spring Framework 7 baseline.
As a compatibility baseline, I checked the repository's existing Spring Framework 6 build path first. Spring Framework 6 is the first Spring Framework major version that uses the Jakarta Servlet API, and the Dubbo repository already provides a `spring-6` Maven profile.
Validating this baseline helps distinguish a pre-existing `javax.servlet` / `jakarta.servlet` compatibility gap from a regression introduced specifically by Spring Framework 7 or Spring Boot 4.
This check showed that `dubbo-rest-spring` already fails to compile against Spring Framework 6.2.18 because it passes `javax.servlet` types to Spring APIs that require `jakarta.servlet` types.
Therefore, although the issue was discovered during Spring Boot 4 compatibility work, it is not specific to Spring Boot 4. It is independently reproducible with:
```text
Spring Framework 6.2.18
Apache Dubbo 3.3
```
It can consequently also affect Spring Boot 3 applications that explicitly use this REST Spring MVC integration.
The same incompatibility is relevant to Spring Boot 4 / Spring Framework 7, because Spring Framework 7 also uses the Jakarta Servlet API and does not restore the old `javax.servlet` method descriptors.
## Root-cause observation
The `dubbo-rest-spring` POM currently declares:
```xml
javax.servlet
javax.servlet-api
provided
```
The following classes directly use
`javax.servlet.http.HttpServletRequest`:
- `org.apache.dubbo.rpc.protocol.tri.rest.support.spring.HandlerInterceptorAdapter`
- `org.apache.dubbo.rpc.protocol.tri.rest.support.spring.SpringMiscArgumentResolver`
`HandlerInterceptorAdapter` passes `javax.servlet` request and response objects to these Spring MVC methods:
```text
HandlerInterceptor.preHandle(...)
HandlerInterceptor.postHandle(...)
HandlerInterceptor.afterCompletion(...)
```
`SpringMiscArgumentResolver` passes a `javax.servlet.http.HttpServletRequest` to:
```text
ServletWebRequest(...)
```
With Spring Framework 5, the relevant Spring APIs use:
```text
javax.servlet.http.HttpServletRequest
javax.servlet.http.HttpServletResponse
```
With Spring Framework 6, the Spring class names remain largely unchanged, but the corresponding JVM method and constructor descriptors use:
```text
jakarta.servlet.http.HttpServletRequest
jakarta.servlet.http.HttpServletResponse
```
A `javax.servlet.http.HttpServletRequest` is therefore not assignable to the Spring Framework 6 API parameter `jakarta.servlet.http.HttpServletRequest`.
This is a compile-time API incompatibility, not only a difference in Maven dependency names.
## Impact scope
Confirmed impact:
- building `org.apache.dubbo:dubbo-rest-spring` sources against Spring Framework 6;
- Spring Boot 3 applications that use the affected Dubbo Triple REST Spring MVC adapter paths;
- repository reactor builds that include `dubbo-rest-spring` when the existing `spring-6` profile is enabled.
The same incompatibility is also a compatibility blocker for users planning to continue using this integration with Spring Boot 4 / Spring Framework 7.
This report does not claim that every Spring Boot starter user is affected. The regular Spring Boot starter does not directly depend on `dubbo-rest-spring`. The primary affected users are applications that explicitly enable or depend on the REST Spring MVC integration and use the affected adapter paths.
## Compatibility constraints
The current implementation remains valid for Spring Framework 5 and `javax.servlet`.
A fix should therefore preserve the following compatibility boundaries:
- existing Spring Framework 5 users continue to receive the `javax.servlet` implementation;
- the existing artifact should not be silently changed into a Jakarta-only artifact;
- Spring Framework 6/7 support should not break the existing Java 8 / Spring Framework 5 build path.
## Possible solution directions
Possible directions include:
1. introducing a separate Spring Framework 6 / Jakarta REST Spring adapter artifact;
2. extracting code that does not depend on the Servlet namespace and keeping thin Spring 5/`javax` and Spring 6/`jakarta` adapters;
3. explicitly declaring this integration unsupported on Spring Framework 6/7, excluding the legacy module from that reactor, and documenting the limitation.
Maintainer guidance would be appreciated on:
- whether Dubbo intends to continue supporting the Triple REST Spring MVC adapters on Spring Framework 6/7;
- whether the preferred strategy is a separate artifact or shared code with version-specific adapters;
- how Spring Framework 5 and Spring Framework 6 artifacts should be selected without breaking existing users.
### Do you have a (mini) reproduction demo?
- [x] Yes, I have a minimal reproduction demo to help resolve this issue more effectively!
### Are you willing to submit a pull request to fix on your own?
- [x] Yes I am willing to submit a pull request on my own!
### Code of Conduct
- [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)
Contributor guide
Research direction
Start with dubbo-plugin/dubbo-rest-spring, especially HandlerInterceptorAdapter.java and SpringMiscArgumentResolver.java, then run the documented Maven spring-6 reactor command. Compare the javax.servlet usage with Spring 6's jakarta.servlet APIs and determine the supported compatibility strategy. Done means the chosen Spring 6 behavior is buildable while Spring 5 compatibility remains unchanged, or the limitation is explicitly documented and excluded.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring-boot
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100