Quarkus中@Produces(APPLICATION_JSON)自动添加数组包裹和逗号问题
问题描述
使用Quarkus开发REST API时,通过@Produces(MediaType.APPLICATION_JSON)异步返回客户列表,结果被自动添加了不必要的数组包裹和错误的逗号分隔符;改用MediaType.TEXT_PLAIN时结果符合预期。需要保留APPLICATION_JSON类型,解决该序列化异常问题。
异常返回结果
[ { "isA": "customerDocument", "createdOn": "2022-10-10T12:29:43", "customerBody": { "customerList": [, { "name": "Batman", "age": 45, "city": "gotham" }, { "name": "superman", "age": 50, "city": "moon" }, ] } }]
期望返回结果
{ "isA": "customerDocument", "createdOn": "2022-10-10T12:29:43", "customerBody": { "customerList": [ { "name": "Batman", "age": 45, "city": "gotham" }, { "name": "superman", "age": 50, "city": "moon" } ] } }
问题代码
@Path("/testData") @GET @Produces(MediaType.APPLICATION_JSON) public Multi<String> test() throws IOException { return Multi.createFrom().items(IOUtils.toString(getClass().getResourceAsStream("/TestJSON.json"), StandardCharsets.UTF_8)); }
解决方案
问题根源
Multi.createFrom().items()方法传入String时,会将其拆分为单个字符的流(因为String实现了CharSequence,被当作字符集合处理)。Quarkus处理Multi类型的JSON响应时,会将整个流序列化为JSON数组,每个元素对应流中的一个字符,最终导致异常的JSON结构。
修复方案
1. 将JSON字符串作为单个元素返回
修改Multi的创建方式,确保流中只有一个完整的JSON字符串元素:
@Path("/testData") @GET @Produces(MediaType.APPLICATION_JSON) public Multi<String> test() throws IOException { String jsonContent = IOUtils.toString(getClass().getResourceAsStream("/TestJSON.json"), StandardCharsets.UTF_8); // 使用item()方法创建包含单个元素的Multi return Multi.createFrom().item(jsonContent); }
2. 改用Uni替代Multi(非流式场景)
如果仅需异步返回单个JSON对象,Uni更适合(专门用于单个异步结果):
@Path("/testData") @GET @Produces(MediaType.APPLICATION_JSON) public Uni<String> test() throws IOException { String jsonContent = IOUtils.toString(getClass().getResourceAsStream("/TestJSON.json"), StandardCharsets.UTF_8); return Uni.createFrom().item(jsonContent); }
3. 返回POJO(推荐最佳实践)
避免直接返回JSON字符串,定义对应Java实体类,让Quarkus自动处理序列化,保证类型安全:
// 定义实体类 public class CustomerDocument { private String isA; private LocalDateTime createdOn; private CustomerBody customerBody; // 构造函数、Getter、Setter } public class CustomerBody { private List<Customer> customerList; // 构造函数、Getter、Setter } public class Customer { private String name; private int age; private String city; // 构造函数、Getter、Setter } // 修改API方法 @Path("/testData") @GET @Produces(MediaType.APPLICATION_JSON) public Uni<CustomerDocument> test() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); // 处理LocalDateTime序列化 CustomerDocument document = objectMapper.readValue( getClass().getResourceAsStream("/TestJSON.json"), CustomerDocument.class ); return Uni.createFrom().item(document); }
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

