SmallRye Mutiny:如何修改Multi<String>末尾元素并生成带包装的JSON
问题分析与解决方案
原代码存在的核心问题
- 未定义变量错误:代码中
generatedEvents变量未声明,属于笔误;即便修正为generatedCustomer,也会导致最后一个客户被重复输出(generatedCustomer中包含带逗号的最后一个客户,lastCustomer又输出去掉逗号的版本)。 - 手动拼接JSON的风险:直接拼接字符串极易出现格式错误(比如引号转义、逗号位置、缩进混乱),且无法处理Customer对象JSON中的特殊字符,破坏整体结构。
- Multi流处理逻辑错误:给所有客户JSON加逗号后再单独修改最后一个的方式,违背了流式处理的设计,且会产生重复数据。
解决方案
根据数据量大小,提供两种可行方案:
方案一:收集所有数据构建完整对象(适合中小数据量)
通过将所有Customer对象收集到列表中,直接构建目标JSON结构的Java对象,再序列化输出,完全避免手动拼接的风险。
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.time.Instant; import java.util.List; public class CustomerGeneratorService { public static Multi<String> generate(final Input input) { final ObjectMapper objectMapper = new ObjectMapper() .registerModule(new JavaTimeModule()); // 支持Instant类型序列化 try { // 收集所有生成的Customer对象到List return Multi.createFrom().publisher(CustomerGenerator.createModels(input)) .collect().asList() .onItem().transform(customers -> { // 构建外层文档对象 CustomerDocument document = new CustomerDocument(); document.setCreatedOn(Instant.now()); document.getCustomerBody().setCustomerList(customers); // 序列化为格式化的JSON字符串 try { return objectMapper.writerWithDefaultPrettyPrinter() .writeValueAsString(document); } catch (JsonProcessingException e) { throw new CustomerException("Failed to serialize customer document", e); } }); } catch (Exception e) { throw new CustomerException("Exception occurred during customer generation", e); } } // 对应目标JSON的DTO类 static class CustomerDocument { private String isA = "customerDocument"; private Instant createdOn; private CustomerBody customerBody = new CustomerBody(); // Getters & Setters public String getIsA() { return isA; } public void setIsA(String isA) { this.isA = isA; } public Instant getCreatedOn() { return createdOn; } public void setCreatedOn(Instant createdOn) { this.createdOn = createdOn; } public CustomerBody getCustomerBody() { return customerBody; } public void setCustomerBody(CustomerBody customerBody) { this.customerBody = customerBody; } static class CustomerBody { private List<Object> customerList; // 若有Customer实体类,替换为List<Customer> // Getters & Setters public List<Object> getCustomerList() { return customerList; } public void setCustomerList(List<Object> customerList) { this.customerList = customerList; } } } }
方案二:流式输出(适合大数据量,避免内存占用)
通过Multi.index()跟踪元素位置,仅给非第一个客户的JSON添加前置逗号,配合流式拼接首尾结构,实现无内存压力的输出。
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.time.Instant; public class CustomerGeneratorService { public static Multi<String> generate(final Input input) { final ObjectMapper objectMapper = new ObjectMapper() .registerModule(new JavaTimeModule()); try { // 生成JSON开头部分 String start = String.format("{\n \"isA\": \"customerDocument\",\n \"createdOn\": \"%s\",\n \"customerBody\": {\n \"customerList\": [\n", Instant.now().toString()); // 处理每个Customer,根据索引决定是否添加前置逗号 Multi<String> customerEntries = Multi.createFrom().publisher(CustomerGenerator.createModels(input)) .index() // 获取带索引的元素(Tuple2<Long, Customer>) .onItem().transform(tuple -> { try { String customerJson = objectMapper.writerWithDefaultPrettyPrinter() .writeValueAsString(tuple.getItem2()); // 第一个元素不加前置逗号,后续元素添加 return tuple.getItem1() > 0 ? ",\n " + customerJson : " " + customerJson; } catch (JsonProcessingException e) { throw new CustomerException("Failed to serialize customer", e); } }); // 生成JSON结尾部分 String end = "\n ]\n }\n}"; // 拼接所有流式部分 return Multi.createBy().concatenating() .streams(Multi.createFrom().items(start), customerEntries, Multi.createFrom().items(end)); } catch (Exception e) { throw new CustomerException("Exception occurred during customer generation", e); } } }
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

