是否可以根据调用的API端点启用/禁用自定义解串器?

时间:2019-06-06 11:23:35

标签: json jackson retrofit2

我正在访问具有两种端点的JSON API:

  • 第一种返回相同类型的对象列表(症状,慢性疾病...)

  • 第二种(搜索功能)返回混合混合的不同类型对象的列表(这些类型与第一种API可以返回的类型相同)

在第二种情况下,列表的每个项目都有一个类型字段,该字段告诉对象的类型。在第一种情况下,该字段不存在。

我想将默认的反序列化器用于第一种API,并将自定义反序列化器用于第二种API。有可能吗?

如果我仅使用默认的反序列化器,则第一种API调用将起作用,但无法执行搜索。

如果启用以下解串器,搜索将起作用,但是在使用第一种API时也会使用解串器,并且由于缺少类型字段而失败。

我要使用的自定义解串器:

class SearchableItemDeserializer : JsonDeserializer<SearchableItem>() {

    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): SearchableItem {
        val root : JsonNode = p.readValueAsTree()
        val type : String = root.get("type").asText()
        when(type){
            "symptom" -> {
                return ObjectMapper().readValue(root.asText(), Symptom::class.java)
        }
            "symptom_group" -> {
                return ObjectMapper().readValue(root.asText(), SymptomGroup::class.java)
            }
            "diagnosis" -> {
                return ObjectMapper().readValue(root.asText(), Diagnose::class.java)
            }
            "chronic_disease" -> {
                return ObjectMapper().readValue(root.asText(), ChronicDisease::class.java)
            }
        }
        throw Exception("Unable to deserialize type $type")
    }
}

症状,症状组,诊断和慢性疾病共有的接口:

@JsonDeserialize(using = SearchableItemDeserializer::class)
interface SearchableItem

1 个答案:

答案 0 :(得分:1)

有可能。您可以扩展Converter.Factory来创建您的自定义转换器。可能最愚蠢和直接的方法是在“ requestBodyConverter”或“ responseBodyConverter”方法中添加对特定改装批注的检查。

类似的东西:

class CustomConverter : Converter.Factory() {

    override fun responseBodyConverter(type: Type,
                                       annotations: Array<Annotation>,
                                       retrofit: Retrofit): Converter<ResponseBody, *>? {
        return responseConverter(*annotations)
                .responseBodyConverter(type, annotations, retrofit)
    }

    private fun responseConverter(vararg methodAnnotations: Annotation): Converter.Factory {
        return when {
            endpoint1(*methodAnnotations) -> converter1
            endpoint2(*methodAnnotations) -> converter2
            else -> defaultConverter
        }
    }

    override fun requestBodyConverter(type: Type,
                                      parameterAnnotations: Array<Annotation>,
                                      methodAnnotations: Array<Annotation>,
                                      retrofit: Retrofit): Converter<*, RequestBody>? {
   //same approach here
    }

fun endpoint1(vararg annotations: Annotation): Boolean {
   //condition check here
}

fun endpoint2(vararg annotations: Annotation): Boolean {
   //and here (if needed)
}

只需添加端点1/2的实现(可能只是将@Get()内容与某些模式或类似内容进行比较),并对requestConverter重复相同的指令即可。

准备好后,只需将其添加到改造中即可

        return Retrofit.Builder()
                .baseUrl(url)
                .client(client)
                .addConverterFactory(CustomConverter())
                .build()