You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

第三方API转自定义Java对象后,Controller返回JSON无字段名问题

问题:Controller返回的JSON无字段名,仅为嵌套数组

我把第三方API的响应解析成自定义Java类,解析过程没问题,但自己的Controller返回的JSON里没有对象的字段名,只有数组嵌套数组的结构,和原第三方API的响应格式一样。代码里的Getter、Setter都正常工作。

服务层解析方法

public List<Kline> klines(String symbol, String interval) {
    try {
        LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
        parameters.put("symbol", symbol);
        parameters.put("interval", interval);
        String result = client.createMarket().klines(parameters);
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(result, new TypeReference<List<Kline>>() { });
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Controller接口

@GetMapping("/klines")
public List<Kline> klines() {
    return service.klines("BTCUSDT", "1h");
}

返回的JSON格式(无字段名)

返回内容为嵌套数组结构,示例:[[1690000000, 30000, 31000, ...], [...]],每个子数组对应一个Kline对象,但没有字段名标识。

我的Kline POJO类

@Data
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({ "openTime", "open", "high", "low", "close", 
"volume", "closeTime", "quoteAssetVolume",
    "numberOfTrades", "takerBuyBaseAssetVolume", 
"takerBuyQuoteAssetVolume" })
@JsonIgnoreProperties(ignoreUnknown = true)
public class Kline {

private Long openTime;

private double open;

private double high;

private double low;

private double close;

private double volume;

private Long closeTime;

private double quoteAssetVolume;

private int numberOfTrades;

private double takerBuyBaseAssetVolume;

private double takerBuyQuoteAssetVolume;

}

解决方法

问题出在@JsonFormat(shape = JsonFormat.Shape.ARRAY)注解上——它是双向生效的:既会让Jackson把第三方的数组格式反序列化成Kline对象,也会让Jackson把Kline对象序列化成数组格式返回给前端。

要实现“反序列化用数组转对象,序列化用对象转带字段名的JSON”,有两种简单方案:

方案1:拆分DTO和业务类

  • 新建一个KlineDto类,保留@JsonFormat(shape = JsonFormat.Shape.ARRAY)和@JsonPropertyOrder注解,专门用来接收第三方API的数组响应;
  • 业务用的Kline类去掉这两个注解,只保留@Data和@JsonIgnoreProperties;
  • 在服务层把List<KlineDto>转换成List<Kline>再返回:
// 示例转换逻辑
List<KlineDto> dtoList = objectMapper.readValue(result, new TypeReference<List<KlineDto>>() { });
return dtoList.stream().map(dto -> {
    Kline kline = new Kline();
    BeanUtils.copyProperties(dto, kline);
    return kline;
}).collect(Collectors.toList());

方案2:自定义反序列化器(无需额外类)

去掉Kline类上的@JsonFormat(shape = JsonFormat.Shape.ARRAY),然后给Kline类添加@JsonDeserialize(using = KlineDeserializer.class),自定义一个反序列化器处理数组格式:

public class KlineDeserializer extends JsonDeserializer<Kline> {
    @Override
    public Kline deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        Kline kline = new Kline();
        kline.setOpenTime(node.get(0).asLong());
        kline.setOpen(node.get(1).asDouble());
        kline.setHigh(node.get(2).asDouble());
        kline.setLow(node.get(3).asDouble());
        kline.setClose(node.get(4).asDouble());
        kline.setVolume(node.get(5).asDouble());
        kline.setCloseTime(node.get(6).asLong());
        kline.setQuoteAssetVolume(node.get(7).asDouble());
        kline.setNumberOfTrades(node.get(8).asInt());
        kline.setTakerBuyBaseAssetVolume(node.get(9).asDouble());
        kline.setTakerBuyQuoteAssetVolume(node.get(10).asDouble());
        return kline;
    }
}

这样反序列化时用自定义逻辑把数组转成对象,序列化时Jackson会默认输出带字段名的JSON结构。


内容的提问来源于stack exchange,提问作者BitQueen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:37:04