如何为RestTemplate返回的Map<*,*>声明正确类型的变量?
解决Kotlin中RestTemplate返回Map类型不匹配的编译错误
我懂你遇到的这个类型推断坑了,RestTemplate返回的Map<*,*>!(平台星号投影类型)和你声明的Map<Any?, Any?>确实不兼容,下面给你几个实际可运行的代码方案,直接就能用:
方案1:直接匹配平台投影类型
如果暂时不确定返回的Map具体键值类型,可以直接把userAttributes声明为和返回值一致的类型:
// 允许body为null的情况,用可空类型 var userAttributes: Map<*, *>? = mapOf() val responseEntity = restTemplate.exchange(userInfoEndpointUri, HttpMethod.GET, entity, Map::class.java) userAttributes = responseEntity.body
如果能确定接口返回的body一定不为null,也可以用非空类型加断言(注意:如果实际返回null会抛出空指针异常,谨慎使用):
var userAttributes: Map<*, *> = mapOf() val responseEntity = restTemplate.exchange(userInfoEndpointUri, HttpMethod.GET, entity, Map::class.java) userAttributes = responseEntity.body!!
方案2:指定具体泛型类型(推荐)
如果知道接口返回的Map键值类型(比如键是String,值是任意可空类型),可以用ParameterizedTypeReference来明确告诉RestTemplate返回的泛型类型,这样就能避免星号投影:
// 声明为你实际需要的类型,比如键是String,值是Any? var userAttributes: Map<String, Any?> = mapOf() val responseEntity = restTemplate.exchange( userInfoEndpointUri, HttpMethod.GET, entity, object : ParameterizedTypeReference<Map<String, Any?>>() {} ) // 用?:处理body为null的情况,给个默认空Map userAttributes = responseEntity.body ?: mapOf()
这个方案的好处是能获得编译期类型检查,后续使用userAttributes时不用再做额外的类型转换,代码更安全。
方案3:安全转换到目标类型
如果你一定要保留Map<Any?, Any?>的声明,可以用Kotlin的安全类型转换来兼容:
var userAttributes: Map<Any?, Any?> = mapOf() val responseEntity = restTemplate.exchange(userInfoEndpointUri, HttpMethod.GET, entity, Map::class.java) // as? 会尝试转换,失败则返回null,再用?:给默认值 userAttributes = responseEntity.body as? Map<Any?, Any?> ?: mapOf()
为什么会出现这个错误?
简单说,Map::class.java在Java/Kotlin交互中会丢失泛型信息,RestTemplate只能返回Map<*,*>!这种平台类型(星号表示任意类型,!表示编译器不确定是否可空),而你声明的Map<Any?, Any?>是明确的可空键值类型,两者无法直接赋值,所以需要上面的几种适配方式。
内容的提问来源于stack exchange,提问作者Aubergine
相关产品推荐
相关产品推荐

