使用Rest-Assured Kotlin扩展提取Spring Page返回结果中嵌套的POJO对象
RestAssured返回值提取问题解答
1. 单对象场景解析正常的原因
as(BookDetailsView::class.java)走的是RestAssured完整的响应体反序列化逻辑,会默认调用你配置的序列化框架(通常是Jackson)处理整个响应体。如果是Spring Boot测试环境,默认会复用Spring上下文内的ObjectMapper实例,已经加载了Kotlin数据类、UUID类型的序列化规则,因此可以直接把整个JSON结构映射为指定的POJO对象。
2. path()泛型不生效的原因
RestAssured的path()方法的泛型参数仅用于编译期的类型强制转换,JVM运行时泛型会被擦除,JsonPath底层无法获取到List<BookDetailsView>的实际泛型参数类型。默认情况下JsonPath只会把JSON节点映射为JDK基础类型:JSON对象转LinkedHashMap、JSON数组转ArrayList、基础数值转对应Java包装类,不会主动触发自定义POJO的反序列化逻辑,因此拿到的列表元素都是LinkedHashMap类型,强转就会抛出类型转换异常。
3. 嵌套列表正常提取的配置方案
首先需要对齐RestAssured和Spring的序列化配置,再用支持泛型类型传递的重载方法提取:
- 第一步:全局配置RestAssured的ObjectMapper,和Spring使用的实例保持一致,保证序列化规则完全对齐:
// 测试类初始化时执行,applicationContext为Spring测试上下文实例 RestAssured.config = RestAssured.config() .objectMapperConfig( ObjectMapperConfig.objectMapperConfig() .jackson2ObjectMapperFactory { _, _ -> applicationContext.getBean(ObjectMapper::class.java) } )
- 第二步:提取泛型列表时使用带
TypeRef的getObject方法,手动传递泛型类型信息:
import io.restassured.common.mapper.TypeRef val content = response.jsonPath() .getObject<List<BookDetailsView>>("content", object : TypeRef<List<BookDetailsView>>() {})
注意:需要确保项目已引入com.fasterxml.jackson.module:jackson-module-kotlin依赖,否则Jackson无法正常反序列化Kotlin数据类。
4. 其他更合理的嵌套POJO提取方案
有两种更易维护的可选方案:
- 方案1:先反序列化整个响应体再提取字段
定义简化的分页接收DTO,直接把整个响应反序列化后取content字段,不需要写JsonPath:
// 仅保留需要的字段即可,不需要完全实现Spring的Page接口 data class SimplePage<T>(val content: List<T> = emptyList()) val page = response.`as`(object : TypeRef<SimplePage<BookDetailsView>>() {}) val content = page.content
- 方案2:封装Kotlin扩展函数简化调用
利用Kotlin的reified泛型特性封装通用提取方法,省去每次手动写TypeRef的冗余代码:
inline fun <reified T> ExtractableResponse<*>.extractListByPath(path: String): List<T> { return this.jsonPath().getObject(path, object : TypeRef<List<T>>() {}) } // 调用示例 val content = response.extractListByPath<BookDetailsView>("content")
内容的提问来源于stack exchange,提问作者AwesomeTown
相关产品推荐
相关产品推荐

