Quarkus中Vertx JsonObject.mapTo映射嵌套JsonObject为空的问题求助
Vertx JsonObject.mapTo 嵌套JsonObject映射为空问题解决
问题描述
在Quarkus框架中使用Vertx的JsonObject.mapTo方法将JSON对象映射为自定义TelemetryDto实体类时,发现嵌套的options字段(类型为JsonObject)被映射为空对象{},而非预期的嵌套JSON内容。
相关代码
TelemetryDto实体类
package com.abc.telemetry.dto; import io.vertx.core.json.JsonObject; public class TelemetryDto { private String clientId; private String commandId; private String deviceRef; private String telemetryAttributeRef; private JsonObject options; public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getCommandId() { return commandId; } public void setCommandId(String commandId) { this.commandId = commandId; } public String getDeviceRef() { return deviceRef; } public void setDeviceRef(String deviceRef) { this.deviceRef = deviceRef; } public String getTelemetryAttributeRef() { return telemetryAttributeRef; } public void setTelemetryAttributeRef(String telemetryAttributeRef) { this.telemetryAttributeRef = telemetryAttributeRef; } public JsonObject getOptions() { return options; } public void setOptions(JsonObject options) { this.options = options; } public TelemetryDto() { } public TelemetryDto(String clientId, String commandId, String deviceRef, String telemetryAttributeRef, JsonObject options) { this.clientId = clientId; this.commandId = commandId; this.deviceRef = deviceRef; this.telemetryAttributeRef = telemetryAttributeRef; this.options = options; } @Override public String toString() { return "TelemetryDto{" + "clientId='" + clientId + '\'' + ", commandId='" + commandId + '\'' + ", deviceRef='" + deviceRef + '\'' + ", telemetryAttributeRef='" + telemetryAttributeRef + '\'' + ", options=" + options + '}'; } }
业务处理代码
package com.abc.telemetry.service; import com.abc.telemetry.dto.TelemetryDto; import io.quarkus.logging.Log; import io.quarkus.vertx.ConsumeEvent; import io.vertx.core.json.DecodeException; import io.vertx.core.json.JsonObject; import org.apache.commons.lang3.Validate; import javax.enterprise.context.ApplicationScoped; import javax.validation.ConstraintViolationException; @ApplicationScoped public class WidgetControlActionProcessor { /* * this is the lister to the Widget control action events * after reserving action, this method responsible handle further processing */ @ConsumeEvent("widget-control-action-feed") public void widgetControlActionConsumer(String message) { Log.info("widget-control-action-feed: Reserved widget control action: " + message); Log.debug("Reserved action: " + message); try { JsonObject jsonMessage = new JsonObject(message); // Get telemetryDto and send to process Log.info("json object: " + jsonMessage); processWidgetControlAction(jsonMessage.mapTo(TelemetryDto.class)); } catch (DecodeException e) { Log.error("Can't process action: " + e.getMessage()); Log.debug(e); } catch (ConstraintViolationException e) { Log.error("Invalid message type: " + e.getMessage()); } } private void processWidgetControlAction(TelemetryDto telemetryDto) { Log.info("telemetry object: " + telemetryDto); } @Scheduled(every = "10s") public void we() { publishTelemetryToDashboard("widget-control-action-feed", "{\n" + " \"clientId\": \"fgfgf1\",\n" + " \"commandId\": 1,\n" + " \"deviceRef\": \"emulator\",\n" + " \"telemetryAttributeRef\":\"abc\",\n" + " \"options\": {\n" + " \"username\": \"nimrekha\",\n" + " \"state\": \"0\"\n" + " }\n" + "}"); } }
日志信息
2023-03-09 17:57:25,023 INFO traceId=c02b65fa0aba9f68ee6ea84481d92689, parentId=d9dff4c54d0af324, spanId=5d326389ab863d8f, sampled=true [co.abc.tel.ser.WidgetControlActionProcessor] [widgetControlActionConsumer] (vert.x-eventloop-thread-3) widget-control-action-feed: Reserved widget control action: { "clientId": "fgfgf1", "commandId": 1, "deviceRef": "emulator", "telemetryAttributeRef":"abc", "options": { "username": "nimrekha", "state": "0" } } 2023-03-09 17:57:25,033 INFO traceId=c02b65fa0aba9f68ee6ea84481d92689, parentId=d9dff4c54d0af324, spanId=5d326389ab863d8f, sampled=true [co.abc.tel.ser.WidgetControlActionProcessor] [widgetControlActionConsumer] (vert.x-eventloop-thread-3) json object: {"clientId":"fgfgf1","commandId":1,"deviceRef":"emulator","telemetryAttributeRef":"abc","options":{"username":"nimrekha","state":"0"}} 2023-03-09 17:57:25,053 INFO traceId=c02b65fa0aba9f68ee6ea84481d92689, parentId=d9dff4c54d0af324, spanId=5d326389ab863d8f, sampled=true [co.abc.tel.ser.WidgetControlActionProcessor] [processWidgetControlAction] (vert.x-eventloop-thread-3) telemetry object: TelemetryDto{clientId='fgfgf1', commandId='1', deviceRef='emulator', telemetryAttributeRef='abc', options={}}
解决方案
方法一:手动提取嵌套JsonObject
直接绕过mapTo对嵌套字段的自动映射,手动从原JsonObject中提取options并设置到Dto对象:
JsonObject jsonMessage = new JsonObject(message); TelemetryDto telemetryDto = jsonMessage.mapTo(TelemetryDto.class); // 手动设置options字段 telemetryDto.setOptions(jsonMessage.getJsonObject("options")); processWidgetControlAction(telemetryDto);
这种方式简单直接,不需要修改实体类或依赖,适合快速解决问题。
方法二:添加Jackson注解增强自动映射
Vertx的mapTo在Quarkus环境中默认依赖Jackson处理序列化,给options字段添加@JsonProperty注解明确映射关系:
package com.abc.telemetry.dto; import io.vertx.core.json.JsonObject; import com.fasterxml.jackson.annotation.JsonProperty; public class TelemetryDto { // ... 其他字段不变 @JsonProperty("options") private JsonObject options; // ... 其他方法不变 }
确保项目中已包含Quarkus的Jackson扩展(默认已集成,若缺失可添加pom依赖):
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency>
方法三:使用Jackson ObjectMapper直接转换
完全绕过Vertx的mapTo,使用Jackson的ObjectMapper直接解析JSON字符串到Dto,这种方式对嵌套对象的支持更完善:
import com.fasterxml.jackson.databind.ObjectMapper; // ... try { ObjectMapper mapper = new ObjectMapper(); TelemetryDto telemetryDto = mapper.readValue(message, TelemetryDto.class); processWidgetControlAction(telemetryDto); } catch (IOException e) { Log.error("JSON解析失败: " + e.getMessage()); }
若需要支持Vertx的JsonObject类型,需添加vertx-jackson-databind依赖:
<dependency> <groupId>io.vertx</groupId> <artifactId>vertx-jackson-databind</artifactId> </dependency>
内容的提问来源于stack exchange,提问作者Kavishka Madhushan
相关产品推荐
相关产品推荐

