Feign使用POJO作为@QueryMap参数触发IllegalStateException报错求助
解决Feign中@QueryMap使用数据类抛出IllegalStateException的问题
我之前也踩过这个坑!Feign原生的@QueryMap注解只支持Map类型的参数,所以直接传入Kotlin数据类(比如你的OrderBookQuery)就会触发那个IllegalStateException。不过有几个简单的办法能搞定这个问题,按推荐程度排序:
方法1:用@JacksonQueryMap替代@QueryMap
OpenFeign官方提供了Jackson扩展模块,专门用来支持将POJO(包括Kotlin数据类)自动序列化为查询参数。这是最省心的方案。
步骤:
- 先确保你的项目依赖里包含了
feign-jackson模块:- Gradle:
implementation 'io.github.openfeign:feign-jackson:12.+' - Maven:
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-jackson</artifactId> <version>12.0</version> </dependency>
- Gradle:
- 修改你的Feign接口,把
@QueryMap换成@JacksonQueryMap:import feign.jackson.JacksonQueryMap interface MarketDataRestClient { @RequestLine("GET /api/v1/depth") fun getOrderBook(@JacksonQueryMap orderBookQuery: OrderBookQuery) : OrderBook } data class OrderBookQuery(val symbol: String, val limit: Int? = 100)
这样Feign就能自动把OrderBookQuery的字段转换成?symbol=xxx&limit=xxx的查询参数,还会自动忽略null值(比如你不传limit的话,就不会生成limit参数)。
方法2:手动将数据类转为Map
如果不想引入额外依赖,可以自己把数据类转换成Map类型,再传给@QueryMap。
示例代码:
// 给OrderBookQuery写个扩展函数,转成过滤掉null值的Map fun OrderBookQuery.toQueryMap(): Map<String, Any> { return mutableMapOf<String, Any>().apply { put("symbol", symbol) limit?.let { put("limit", it) } } } // 修改Feign接口接收Map参数 interface MarketDataRestClient { @RequestLine("GET /api/v1/depth") fun getOrderBook(@QueryMap orderBookQuery: Map<String, Any>) : OrderBook } // 调用的时候转成Map val query = OrderBookQuery("BTCUSDT", 50) client.getOrderBook(query.toQueryMap())
这个方法适合简单的数据类,要是字段多的话写起来有点麻烦。
方法3:自定义QueryMapEncoder
如果需要全局支持POJO转查询参数,可以自定义一个QueryMapEncoder,用Jackson或者其他序列化工具来实现,然后配置到Feign客户端里。
示例代码:
import com.fasterxml.jackson.databind.ObjectMapper import feign.QueryMapEncoder class JacksonQueryMapEncoder(private val objectMapper: ObjectMapper) : QueryMapEncoder { override fun encode(mapObject: Any): Map<String, Any> { // 把POJO转成Map return objectMapper.convertValue(mapObject, Map::class.java) as Map<String, Any> } } // 构建Feign客户端时配置这个编码器 val client = Feign.builder() .queryMapEncoder(JacksonQueryMapEncoder(ObjectMapper())) .target(MarketDataRestClient::class.java, "https://your-api-base-url.com")
这样你的原始接口代码不用改,@QueryMap就能直接接收数据类了。
内容的提问来源于stack exchange,提问作者doublemc
相关产品推荐
相关产品推荐

