`WebClient` with default codecs drops `ProblemDetail` extension members
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
- #37507 của @zsewasdsdsd — đã đóng, không merge
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 70/100
Hướng nghiên cứu
Lỗ hổng nằm ở JacksonJsonDecoder trong org.springframework.http.codec.json; khác với JacksonJsonEncoder, lớp này không bao giờ đăng ký ProblemDetailJacksonMixin trong cả constructor mặc định lẫn constructor nhận JsonMapper.Builder. Trước tiên hãy so sánh hai lớp này cạnh nhau, sau đó xem các test codec hiện có cho việc giải mã ProblemDetail để xác định nơi đặt một test tương tự cho decoder. Hoàn thành khi một WebClient được xây dựng với codec mặc định giữ nguyên các thành viên mở rộng trong getProperties(), được tái hiện bằng mẫu noojung/webclient-problemdetail-mixin-repro. Lưu ý rằng một PR (#37507) đã được mở và đóng mà không được hợp nhất, vì vậy hãy kiểm tra luồng thảo luận trước khi tạo PR trùng lặp.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Overview
While checking that RestClient and WebClient decode ProblemDetail responses correctly, I noticed that a WebClient created with the default codecs (WebClient.create() or WebClient.builder()) drops RFC 9457 extension members: getProperties() returns null, while the standard members are decoded correctly.
This worked with Spring Framework 6.2 (Spring Boot 3.5), so it looks like a regression introduced with the Jackson 3 codecs.
Versions tested
- Spring Framework 7.0.9 (Spring Boot 4.1.1, Jackson 3): extension members are lost
- Spring Framework 6.2.11 (Spring Boot 3.5.6, Jackson 2): works as expected
Reproducer
With the sample server running on port 8080, GET /orders/42 returns HTTP 404 with Content-Type: application/problem+json and the following body:
{
"type": "https://example.com/problems/order-not-found",
"title": "Order Not Found",
"status": 404,
"detail": "Order 42 does not exist",
"instance": "/orders/42",
"errorCode": "ORDER_NOT_FOUND",
"orderId": 42
}
The extension members are lost when decoding the response:
WebClient webClient = WebClient.create("http://localhost:8080");
// Also reproduces with:
// WebClient.builder().baseUrl("http://localhost:8080").build();
WebClientResponseException.NotFound exception = assertThrows(
WebClientResponseException.NotFound.class,
() -> webClient.get()
.uri("/orders/42")
.retrieve()
.bodyToMono(Order.class)
.block());
ProblemDetail problemDetail = exception.getResponseBodyAs(ProblemDetail.class);
assertThat(problemDetail).isNotNull();
assertThat(problemDetail.getProperties())
.containsEntry("errorCode", "ORDER_NOT_FOUND")
.containsEntry("orderId", 42);
// 6.2.11: passes
// 7.0.9: fails because getProperties() returns null
A complete sample (Spring MVC server + WebClient/RestClient tests) is available here: https://github.com/noojung/webclient-problemdetail-mixin-repro
Running ./gradlew test starts the server automatically and fails webClientCreateShouldPreserveProblemDetailProperties and webClientBuilderShouldPreserveProblemDetailProperties.
For comparison, RestClient.create() and the WebClient.Builder auto-configured by Spring Boot both keep the extension members, since JacksonJsonHttpMessageConverter registers the mixin and Boot configures the codecs with a JsonMapper that has it (spring-projects/spring-boot#47298).
Analysis
JacksonJsonEncoder and JacksonJsonHttpMessageConverter register ProblemDetailJacksonMixin in their default and JsonMapper.Builder-based constructors, but JacksonJsonDecoder does not. Since FAIL_ON_UNKNOWN_PROPERTIES is disabled by default in Jackson 3, the extension members are ignored without any error.
With Jackson 2, the default Jackson2JsonDecoder created its mapper through Jackson2ObjectMapperBuilder, which registers the mixin.
Workaround
WebClient webClient = WebClient.builder()
.codecs(configurer -> configurer.defaultCodecs().jacksonJsonDecoder(new JacksonJsonDecoder(
JsonMapper.builder().addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class))))
.build();
Related issues
- #35597
- spring-projects/spring-boot#47298
Would registering ProblemDetailJacksonMixin in the default and JsonMapper.Builder-based constructors of JacksonJsonDecoder, the same way as in JacksonJsonEncoder, be the right fix? If so, I would be happy to submit a pull request.
- Ngôn ngữ chính
- Java
- Star
- 60.3k
- Fork
- 38.7k
- Merge trung bình
- 1 ngày 9 giờ
- Pull request đã merge (30 ngày)
- 34
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của spring-projects/spring-framework
-
`YamlProcessor.getFlattenedMap` with `includeEmpty` returns a `null` key for an empty root mappingCó thể làm lại được @erfannvb đã nhận 7 ngày trước và không có pull request nào đang mở. Đang mởstatus: waiting-for-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
spring-projects/spring-framework#37522 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
StandardApiVersionDeprecationHandler generates nonconforming Sunset HTTP datesCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mởstatus: waiting-for-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
spring-projects/spring-framework#37486 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
FastByteArrayOutputStream input stream rejects valid skip(long) argumentsCó thể làm lại được @hickey-ai đã nhận 10 ngày trước và không có pull request nào đang mở. Đang mởstatus: waiting-for-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
spring-projects/spring-framework#37471 · 6 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
LinkedCaseInsensitiveMap.keySet().remove returns false after removing a null-valued entryCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mởstatus: waiting-for-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
spring-projects/spring-framework#37470 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ServerSentEventHttpMessageReader does not recognize data fields without a colonCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mởin: web status: waiting-for-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
spring-projects/spring-framework#37461 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của spring-projects/spring-framework
Issue tương tự
-
:Search Relevance/Vectors >test-failure needs:risk Team:Search Relevance
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 61/100
elastic/elasticsearch#163668 · 3 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent:working bug follow-up lane:auto
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Sanne/incus-spawn#1765 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Mend: dependency security vulnerability untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 63/100
opensearch-project/data-prepper#7219 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
Maintainer thường phản hồi trong vòng 1 ngày