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

@GetMapping方法返回带方括号JSON的原因及修复方案

问题:单个对象接口返回JSON数组的原因与解决办法

问题场景

控制器代码:

@RestController
public class BillsController {
...
    @GetMapping("get/billById/{billId}")
    Mono<BillDto> getBillById(@PathVariable Long billId) {
        log.info("Request received to fetch Bill with id : " + billId);
        return Mono.just(service.getBillById(billId));
    }
...
}

接口返回的JSON(带数组括号):

[
    {
        "id": 3,
        "customer": "Larry",
        "products": [
            {
                "id": 5,
                "name": "Bike"
            }
        ]
    }
]

Service方法实现:

public BillDto getBillById(Long billId) {
    return modelMapper.map(billRepository.findById(billId).orElseThrow(NullPointerException::new), BillDto.class);
}

客户端消费时报错:

reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize value of type library.dto.BillDto from Array value (token JsonToken.START_ARRAY); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type library.dto.BillDto from Array value (token JsonToken.START_ARRAY)

客户端代码:

Mono<BillDto> billDtoMono = client.getBilById(bill.getId());
billDtoMono.subscribe(BillDto -> {
    log.info(BillDto.toString());
});

注:若在@GetMapping方法内调用subscribe()并直接返回对象,响应格式正常。

原因分析

  1. BillDto类被Jackson识别为集合类型:如果BillDto继承了集合类(如ArrayList)或实现了Iterable接口,Jackson会默认将其序列化为JSON数组,即使它是单个对象。
  2. Repository方法定义错误:若BillRepository的findById方法返回List<Bill>而非Optional<Bill>,modelMapper在映射时可能生成异常结构,导致最终序列化结果为数组(此情况通常伴随类型转换警告)。
  3. Mono包装对象异常:虽然代码中用Mono.just()包装单个对象,但如果service返回的对象实际是集合(如强制类型转换导致),也会引发数组序列化。

解决办法

1. 修正BillDto类定义

检查BillDto是否继承了集合类或实现Iterable接口,若有则移除该继承关系;若必须保留,添加Jackson注解强制序列化为对象:

import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class BillDto {
    // 类字段、构造方法及getter/setter
}

2. 验证Repository方法正确性

确保BillRepository的findById方法返回Optional<Bill>,这是Spring Data JPA的标准定义:

public interface BillRepository extends JpaRepository<Bill, Long> {
    Optional<Bill> findById(Long id);
}

3. 调整控制器返回类型(同步场景)

若service方法是同步实现,可直接返回BillDto而非Mono<BillDto>,避免WebFlux的异步序列化逻辑干扰:

@GetMapping("get/billById/{billId}")
BillDto getBillById(@PathVariable Long billId) {
    log.info("Request received to fetch Bill with id : " + billId);
    return service.getBillById(billId);
}

4. 确认Mono包装的对象类型

通过调试确认service返回的是单个BillDto对象而非集合:

@GetMapping("get/billById/{billId}")
Mono<BillDto> getBillById(@PathVariable Long billId) {
    log.info("Request received to fetch Bill with id : " + billId);
    BillDto dto = service.getBillById(billId);
    log.info("Service返回对象类型: " + dto.getClass()); // 输出应为BillDto而非集合类
    return Mono.just(dto);
}

客户端适配

修正接口返回格式后,现有客户端代码无需修改即可正常解析Mono<BillDto>。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:27:37