如何通过注解为FeignClient特定响应解包根元素?
问题描述
我有一个调用外部服务的FeignClient,代码如下:
interface JiraClient { // ... @RequestMapping(method = [RequestMethod.GET], value = ["\${jira.api.agile}/sprint/{sprintId}/issue"]) fun getIssuesForASprint( @PathVariable("sprintId") sprintId: Int, @RequestParam(name = "startAt", required = false) startAt: Int = 0, @RequestParam(name = "maxResults", required = false) maxResults: Int = MAX_RESULTS ): IssueHolder @RequestMapping(method = [RequestMethod.GET], value = ["\${jira.api.insight}/objectschema/list"]) fun getObjectSchemaList(): List<ObjectSchema> }
对应的ObjectSchema数据类代码:
@JsonIgnoreProperties(ignoreUnknown = true) data class ObjectSchema( @JsonProperty("id") val id: Int, @JsonProperty("name") val name: String?, @JsonProperty("objectSchemaKey") val objectSchemaKey: String?, @JsonProperty("status") val status: String?, @JsonProperty("created") @JsonFormat( shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ) val created: Date?, @JsonProperty("updated") @JsonFormat( shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ) val updated: Date?, @JsonProperty("objectCount") val objectCount: Int?, @JsonProperty("objectTypeCount") val objectTypeCount: Int? )
这个接口无法正常工作,因为外部服务返回的响应包含额外的根元素:
{ "objectschemas": [ { "id": 1, "name": "APPS CATALOG", "objectSchemaKey": "AC", "status": "Ok", "created": "2020-01-01T11:11:11.000Z", "updated": "2020-01-01T11:11:11.000Z", "objectCount": 123, "objectTypeCount": 10 }, { "id": 2, "name": "ORG CATALOG", "objectSchemaKey": "OC", "status": "Ok", "created": "2020-01-01T11:11:11.000Z", "updated": "2020-01-01T11:11:11.000Z", "objectCount": 456, "objectTypeCount": 20 } ] }
对于其他带分页信息的响应,我已经用Holder数据类处理(比如IssueHolder对应包含issues数组的分页响应),但这次希望通过给特定数据类加注解的简单方式,实现根元素objectschemas的解包。这个数据类只用来反序列化,不需要序列化,而且不想在自定义Feign Decoder里加大量逻辑,也没法在FeignClient接口里配置DeserializationFeature.UNWRAP_ROOT_VALUE,想问下最简单的实现方法是什么?
解决方案
最省事的方式是创建一个仅用于反序列化的Holder数据类,用Jackson注解匹配根元素,原有ObjectSchema类完全不用改:
- 新增
ObjectSchemaHolder类:
@JsonRootName("objectschemas") @JsonIgnoreProperties(ignoreUnknown = true) data class ObjectSchemaHolder( @JsonValue val schemas: List<ObjectSchema> )
@JsonRootName指定要匹配的根元素名objectschemas@JsonValue表示这个类的实例直接对应根元素的数组内容,反序列化时会自动把根元素里的数组映射到schemas字段
- 修改FeignClient接口的返回类型:
@RequestMapping(method = [RequestMethod.GET], value = ["\${jira.api.insight}/objectschema/list"]) fun getObjectSchemaList(): ObjectSchemaHolder
- 调用接口时直接取
holder.schemas就能拿到目标列表。
如果不想改接口返回类型,也可以给接口方法的返回值加@JsonDeserialize指定自定义解包器,但这种写法不如Holder类直观,代码量也更多。上面的Holder类方案完全符合你的要求:只用注解实现解包,不用改全局Decoder配置,代码少,而且只服务于反序列化场景。
内容的提问来源于stack exchange,提问作者Jing Li
相关产品推荐
相关产品推荐

