如何解决 Spring Boot 中自定义 ResponseEntity 反序列化失败的问题?
2024-03-30 11:25:30
如何解决自定义 ResponseEntity 反序列化失败的问题
介绍
在使用 Spring Boot 开发 Web 应用程序时,我们经常使用 ResponseEntity
来封装 HTTP 响应。有时候,我们需要定义自定义的 ResponseEntity
子类来满足特定的需求。但是,在反序列化自定义 ResponseEntity
时,可能会遇到问题,尤其是当类具有带参数的构造函数时。
问题:反序列化失败
Spring Boot 使用 Jackson 库进行 JSON 序列化和反序列化。默认情况下,Jackson 会查找具有无参构造函数的类来进行反序列化。但是,如果自定义 ResponseEntity
子类具有带参数的构造函数,Jackson 就无法找到合适的构造函数,从而导致反序列化失败。
解决方案:使用 @JsonCreator
注解
为了解决这个问题,需要在自定义 ResponseEntity
子类中添加 @JsonCreator
注解。此注解告诉 Jackson 使用带参数的构造函数进行反序列化。它指定了应该如何从 JSON 输入中解析参数。
示例:使用 @JsonCreator
考虑以下 CircuitBreakerFallbackMessage
类,它继承了 ResponseEntity
并具有带参数的构造函数:
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.HashMap;
import java.util.Map;
@Getter
public static class CircuitBreakerFallbackMessage extends ResponseEntity<Map<String, String>> {
@JsonCreator
public CircuitBreakerFallbackMessage(String message) {
super(buildMessage(message), HttpStatus.GATEWAY_TIMEOUT);
}
private static Map<String, String> buildMessage(String appName) {
String message = MessageFormat.format("{0} is currently unavailable", appName);
HashMap<String, String> messageMap = new HashMap<>();
messageMap.put("message", message);
return messageMap;
}
}
在 @JsonCreator
注解中,我们指定了使用具有 String
参数的构造函数进行反序列化。
更新测试
在使用 @JsonCreator
注解修复了反序列化问题之后,测试应该能够成功运行:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.WebTestClient;
import java.text.MessageFormat;
import java.util.Map;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
@WebFluxTest(controllers = FallbackController.class)
class FallbackControllerTest {
@Autowired
WebTestClient testClient;
@Test
void testGetFallback() {
String appName = "some-app";
CircuitBreakerFallbackMessage fallbackMessage = testClient
.get()
.uri(MessageFormat.format("/fallback/{0}", appName))
.exchange()
.expectStatus().isEqualTo(HttpStatus.GATEWAY_TIMEOUT)
.expectBody(CircuitBreakerFallbackMessage.class)
.returnResult()
.getResponseBody();
assertThat(fallbackMessage).isNotNull();
Map<String, String> fallbackMessageBody = fallbackMessage.getBody();
assertThat(fallbackMessageBody).isNotNull();
assertThat(fallbackMessage)
.extracting(fallbackMessageBody.get("message"))
.asString()
.containsPattern(Pattern.compile(appName + " (is )?(currently )?unavailable"));
}
}
结论
通过添加 @JsonCreator
注解来显式指定反序列化的构造函数,我们解决了自定义 ResponseEntity
反序列化失败的问题。这确保了 Jackson 可以正确地将 JSON 输入反序列化为我们的自定义 ResponseEntity
子类。
常见问题解答
Q:为什么使用 @JsonCreator
注解?
A:@JsonCreator
注解告诉 Jackson 使用带参数的构造函数进行反序列化。
Q:如果自定义 ResponseEntity
子类没有带参数的构造函数,我该怎么办?
A:在这种情况下,需要手动添加一个无参构造函数,以便 Jackson 能够使用它进行反序列化。
Q:@JsonCreator
注解可以应用于其他类吗?
A:是的,@JsonCreator
注解可以应用于任何需要使用带参数的构造函数进行反序列化的类。
Q:如何使用其他 Jackson 注解来控制反序列化?
A:Jackson 提供了其他注解,例如 @JsonProperty
和 @JsonDeserialize
,它们可以更精细地控制反序列化过程。
Q:在哪里可以找到有关 Jackson 库的更多信息?
A:Jackson 库的官方网站提供了全面的文档和示例:https://fasterxml.github.io/jackson-databind/