Skip to content

[Bug] dubbo-rest-spring is incompatible with Spring Framework 6+ due to a javax/jakarta Servlet API mismatch #16387

Description

@SavitarC

Pre-check

  • I am sure that all the content I provide is in English.

Search before asking

  • I had searched in the issues and found no similar issues.

Apache Dubbo Component

Java SDK (apache/dubbo)

Dubbo Version

Apache Dubbo: 3.3 branch
Verified commit: d0bf5c3
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

This reproduction uses the actual Maven Central artifacts rather than locally reimplemented adapters:

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:

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:

java.lang.NoSuchMethodError:
  HandlerInterceptor.preHandle(
    javax.servlet.http.HttpServletRequest,
    javax.servlet.http.HttpServletResponse,
    java.lang.Object)
  at HandlerInterceptorAdapter.java:71

and:

java.lang.NoSuchMethodError:
  ServletWebRequest.<init>(
    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 d0bf5c3, run:

./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:

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:

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:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <scope>provided</scope>
</dependency>

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:

HandlerInterceptor.preHandle(...)
HandlerInterceptor.postHandle(...)
HandlerInterceptor.afterCompletion(...)

SpringMiscArgumentResolver passes a javax.servlet.http.HttpServletRequest to:

ServletWebRequest(...)

With Spring Framework 5, the relevant Spring APIs use:

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:

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?

  • 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?

  • Yes I am willing to submit a pull request on my own!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedEverything needs help from contributors

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions