Vert.x web 接收请求时反序列化对象 Failed to decode 如何解决?

本文探讨了在使用Vert.x 4.3.1进行web开发时,遇到的POST接口请求体反序列化失败问题,通过引入jackson-databind并切换到DatabindCodec,解决了从LinkedHashMap到自定义对象的转换问题。
摘要由CSDN通过智能技术生成

最近在尝试用 Vert.x 进行 web 开发,发现接口在接收请求体后,反序列化报错,跟进一下原因。

解决方案

引入 jackson-databind
我是用的是 Vert.x 4.3.1,所以引入 jackson-databind 2.13.2.* 版本:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.2.2</version>
</dependency>

排查过程

构造接口

编写一个 Post 接口,将请求体转换为一个对象 NewOrderRequest(对象是个 DTO,只有一些基本的字段定义):

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.sqlclient.Pool;

public class OrderRestAPI {
    
    private final OrderService orderService;

    public OrderRestAPI(Vertx vertx, Router router, Pool pool, JsonObject orderConfig) {
        orderService = new OrderService(vertx, pool, orderConfig);
        router.post("/order").handler(BodyHandler.create().setBodyLimit(256)).respond(this::newOrder);
    }

    private Future<ResponseDTO<NewOrderResponse>> newOrder(RoutingContext ctx) {
        NewOrderRequest newOrderRequest = ctx.body().asPojo(NewOrderRequest.class);
        return orderService.newOrder(newOrderRequest).map(result -> new ResponseDTO<>("OK", result));
    }
}

发现问题

但是在反序列化的时候报错 Failed to decode

22:25:50.048 [vert.x-eventloop-thread-1] ERROR io.vertx.ext.web.RoutingContext - Unhandled exception in router
io.vertx.core.json.DecodeException: Failed to decode
	at io.vertx.core.json.jackson.JacksonCodec.cast(JacksonCodec.java:350) ~[vertx-core-4.3.1.jar:4.3.1]
	at io.vertx.core.json.jackson.JacksonCodec.fromParser(JacksonCodec.java:187) ~[vertx-core-4.3.1.jar:4.3.1]
	at io.vertx.core.json.jackson.JacksonCodec.fromBuffer(JacksonCodec.java:74) ~[vertx-core-4.3.1.jar:4.3.1]
	at io.vertx.core.json.Json.decodeValue(Json.java:119) ~[vertx-core-4.3.1.jar:4.3.1]
	at io.vertx.ext.web.impl.RequestBodyImpl.asPojo(RequestBodyImpl.java:126) ~[vertx-web-4.3.1.jar:4.3.1]
	at io.vertx.ext.web.RequestBody.asPojo(RequestBody.java:115) ~[vertx-web-4.3.1.jar:4.3.1]
	at icu.wwj.web.handler.OrderRestAPI.newOrder(OrderRestAPI.java:25) ~[classes/:?]

跟进代码

查看 Vert.x JacksonCodec 发现,请求体被正常反序列化为了 LinkedHashMap,但是代码中判断,如果反序列化的目标不是 Map 或着 Map 的派生,就抛出 Failed to decode 的错误:
在这里插入图片描述

看到上面的代码首先感到的是奇怪:

  • 为什么非常简单的对象反序列化也无法进行?
  • 是不是我是用 asPojo 的方式不对?

往上层看了下,Vert.x 不出所料地使用了流行的 Jackson,但是 JsonCodec 方法有两个实现:

  • DatabindCodec
  • JacksonCodec
    在这里插入图片描述
    目前运行的进程默认使用了 JacksonCodec,是不是可以切换到 DatabindCodec 试试?

如何切换 Databind 实现?

Vert.x 通过 JacksonFactory 创建 JsonCodec 的实现,先尝试创建 DatabindCodec,如果抛出异常(也就是缺少 databind 相关的类)则创建 JacksonCodec

public class JacksonFactory implements io.vertx.core.spi.JsonFactory {

  public static final JacksonFactory INSTANCE = new JacksonFactory();

  public static final JacksonCodec CODEC;

  static {
    JacksonCodec codec;
    try {
      codec = new DatabindCodec();
    } catch (Throwable ignore) {
      // No databind
      codec = new JacksonCodec();
    }
    CODEC = codec;
  }

  @Override
  public JsonCodec codec() {
    return CODEC;
  }
}

源码链接:https://github.com/eclipse-vertx/vert.x/blob/0bdaecf62dbb14421d0277fbfe3c90a47812f538/src/main/java/io/vertx/core/json/jackson/JacksonFactory.java

vertx-core 在引入 jackson-databind 的时候声明了 optional

    <!-- Jackson -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <optional>true</optional>
    </dependency>

源码链接:https://github.com/eclipse-vertx/vert.x/blob/0bdaecf62dbb14421d0277fbfe3c90a47812f538/pom.xml#L127-L136

由此可以理解:Vert.x Core 引入了 jackson-core 以提供基本的 Json 编解码能力,但对于 Json 与对象映射这类更高级的操作,需要借助 jackson-databind 实现。

那只需要引入 jackson-databind 就能解决问题了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuweijie@apache.org

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值