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

JSON反序列化后如何去除空DTO对象?求替代list.get(1)的方案

解决JSON数组反序列化时无效空对象的问题

问题背景

原JSON返回的是包含两个元素的数组:第一个元素仅含charsetinfo元数据字段,第二个元素是包含engine/timetable/dailytable的业务数据。通过FeignClient反序列化为List<SingleEngineJsonDto>后,列表第一个元素因@JsonIgnoreProperties忽略了charsetinfo,导致所有业务字段为null;第二个元素才是有效数据。当前硬编码list.get(1)获取有效数据的方式被禁止,需要找到可靠的处理方案。

解决方案

方案1:自定义Jackson反序列化器(推荐)

直接在序列化阶段过滤掉仅含charsetinfo的无效对象,让返回的列表只保留有效业务数据。

  1. 编写自定义反序列化器:
public class FilteredSingleEngineJsonDtoListDeserializer extends JsonDeserializer<List<SingleEngineJsonDto>> {
    @Override
    public List<SingleEngineJsonDto> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        ObjectMapper mapper = (ObjectMapper) p.getCodec();
        JsonNode rootNode = mapper.readTree(p);
        List<SingleEngineJsonDto> validDtos = new ArrayList<>();
        
        for (JsonNode node : rootNode) {
            // 仅保留包含业务字段的对象
            if (node.has("engine") || node.has("timetable") || node.has("dailytable")) {
                SingleEngineJsonDto dto = mapper.treeToValue(node, SingleEngineJsonDto.class);
                validDtos.add(dto);
            }
        }
        return validDtos;
    }
}
  1. 在FeignClient的方法上指定该反序列化器:
@FeignClient(value = "engine", url = "engine")
public interface EngineClient {
    // ...其他方法
    @GetMapping
    @JsonDeserialize(using = FilteredSingleEngineJsonDtoListDeserializer.class)
    List<SingleEngineJsonDto> getEngine(URI engineUri, @RequestParam(value = "lang", required = false) String lang);
}

这样反序列化后的列表只会包含有效数据,直接用list.get(0)即可获取目标对象。

方案2:业务层过滤无效对象(快速实现)

如果不想修改序列化逻辑,可在服务层对列表进行过滤,筛选出存在非null业务字段的对象:

@Service
public class EngineParamEngine implements EngineFactoryInterface {

    @Override
    public List<SingleEngineDTO> getEngineObjectPart(List<SingleEngineJsonDto> list){
        return list.stream()
                .filter(dto -> dto.getEngine() != null || dto.getTimetable() != null || dto.getDailytable() != null)
                .findFirst()
                .orElseThrow(() -> new RuntimeException("未找到有效引擎数据"))
                .getEngine();
    }
}

该方案无需改动序列化配置,通过流式处理过滤无效对象,避免了硬编码索引的风险。

方案3:调整DTO结构适配原JSON

若需要保留charsetinfo元数据,可定义顶层DTO统一接收数组中的两种对象:

// 顶层响应DTO
@Getter
@Setter
@ToString
public class EngineResponse {
    private CharsetInfo charsetinfo;
    private List<SingleEngineDTO> engine;
    private List<Timetable> timetable;
    private List<Dailytable> dailytable;
}

// 字符集信息类
@Getter
@Setter
public class CharsetInfo {
    private String name;
}

修改FeignClient返回类型为List<EngineResponse>,之后在业务层筛选出包含业务字段的对象即可。不过该方案仅在需要使用charsetinfo时适用,否则冗余。

注意事项

  • 确保DTO字段与JSON字段名匹配:若JSON中是大写的NAME,DTO中需用@JsonProperty("NAME")标注对应字段,否则会导致映射失败。
  • 自定义反序列化器需确保FeignClient使用的Jackson配置能识别该注解,若使用Spring Boot默认配置则无需额外注册。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:55:24