JPA Projections与DTO接口获取JSON数组时转义字符问题
问题描述
我有一个用于关联查询多表数据的DTO接口HRJobsDTO,定义如下:
public interface HRJobsDTO { String getEditorName(); String getEditorId(); String getBillingMonth(); Integer getEditorWordCount(); Integer getJobCount(); Integer getEmployeeGrade(); Float getGrossPayableAmount(); Float getJobBillingRate(); Float getTaxDeduction(); Float getTaxDeductionAmount(); Float getNetPayableAmount(); String getInvoiceStatus(); String getFreelanceInvoiceId(); }
其中getFreelanceInvoiceId()方法借助MySQL的json_arrayagg函数返回JSON数组,但我尝试将该字段类型改为String、String[]和ArrayList后,返回的响应中该字段始终是带转义字符的字符串形式数组:
"freelanceInvoiceId": "[\"4af9e342-065b-4594-9f4f-a408d5db9819/2022121-95540\", \"4af9e342-065b-4594-9f4f-a408d5db9819/2022121-95540\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\", \"4af9e342-065b-4594-9f4f-a408d5db9819/20221215-53817\"]"
请问如何让该字段返回不含转义字符的纯数组格式?
解决方案
方法1:用Jackson手动解析字符串为数组
在返回数据前,将freelanceInvoiceId的字符串内容解析为List<String>或String[],替换原字段返回:
ObjectMapper objectMapper = new ObjectMapper(); // 假设dto是HRJobsDTO的实例 List<String> invoiceIds = objectMapper.readValue( dto.getFreelanceInvoiceId(), new TypeReference<List<String>>() {} );
如果是Spring环境,也可以在DTO中通过默认方法自动处理:
public interface HRJobsDTO { // 其他方法保持不变 String getFreelanceInvoiceId(); @JsonGetter("freelanceInvoiceId") default List<String> getParsedFreelanceInvoiceId() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(getFreelanceInvoiceId(), new TypeReference<List<String>>() {}); } }
注意要处理JsonProcessingException,可统一捕获或向上抛出。
方法2:修改JPA查询,直接映射为集合
借助Hibernate的JSON类型支持,将查询结果直接映射为List<String>:
- 先添加Hibernate类型依赖(Maven):
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-types-52</artifactId> <version>2.19.2</version> </dependency>
- 修改DTO的字段类型并标注类型:
public interface HRJobsDTO { // 其他方法保持不变 @Type(type = "json") List<String> getFreelanceInvoiceId(); }
- 调整JPA查询,将聚合结果转为JSON类型:
SELECT -- 其他字段 CAST(json_arrayagg(f.invoice_id) AS JSON) AS freelanceInvoiceId FROM your_table -- 关联查询逻辑 GROUP BY ...
这样Hibernate会自动将JSON数组映射为List<String>,返回时直接是纯数组格式。
方法3:自定义JSON反序列化器
在DTO字段上添加@JsonDeserialize注解,指定自定义解析器自动处理:
public interface HRJobsDTO { // 其他方法保持不变 @JsonDeserialize(using = JsonArrayToListDeserializer.class) List<String> getFreelanceInvoiceId(); }
自定义反序列化器实现:
public class JsonArrayToListDeserializer extends JsonDeserializer<List<String>> { @Override public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String jsonStr = p.getText(); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(jsonStr, new TypeReference<List<String>>() {}); } }
这种方式会在序列化响应时自动完成解析,无需手动处理。
方法4:改用JPA关联查询替代聚合函数
如果业务允许,可放弃json_arrayagg,通过JPA的@OneToMany关联关系获取发票ID列表,这样返回的直接是集合类型,不会出现转义问题。但需要调整实体类的关联逻辑,适合数据量较小的场景。
内容的提问来源于stack exchange,提问作者Siddhant Bhandari
相关产品推荐
相关产品推荐

