异常描述
最近按照相关介绍,使用Retrofit进行Http请求处理,并按照其使用说明,定义如下请求接口。
interface NacosOperatorFunc {
@POST("auth/users/login")
rx.Observable<Map<String, Object>> nacosLogin(@Query("username") String username, @Query("password") String password);
@GET("console/server/state")
rx.Observable<Map<String, Object>> nacosVersion(@Query("accessToken") String accessToken, @Query("username") String userName);
}
然后,创建Retrofit,并执行请求。
protected Retrofit createRetrofit() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("http://localhost:8848/nacos/v1/")
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.build();
}
@Test
public void test() {
this.createRetrofit().create(NacosOperatorFunc.class).nacosLogin("nacos", "nacos").forEach(System.out::println);
}
执行test方法时,方法抛出如下异常
java.lang.IllegalArgumentException: Unable to create call adapter for rx.Observable<java.util.Map<java.lang.String, java.lang.Object>>
for method NacosOperatorFunc.nacosLogin
at retrofit2.Utils.methodError(Utils.java:54)
at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:116)
at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:67)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202)
at retrofit2.Retrofit$1.invoke(Retrofit.java:160)
at com.quelongjiang.nacos.config.rxjava.example.$Proxy4.nacosLogin(Unknown Source)
at com.quelongjiang.nacos.config.rxjava.example.RxJavaHttpExample.test(RxJavaHttpExample.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<java.util.Map<java.lang.String, java.lang.Object>>.
Tried:
* retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
* retrofit2.CompletableFutureCallAdapterFactory
* retrofit2.DefaultCallAdapterFactory
at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:272)
at retrofit2.Retrofit.callAdapter(Retrofit.java:237)
at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:114)
... 28 more
问题原因
一顿百度后,给出解决措施是,是依赖版本不对引起。但是,上述代码依赖的版本一致,且都是2.9.0版本。初步分析,应该不是版本问题引起。
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.9.0</version>
</dependency>
无赖之下,自力更生,自行debug,寻求原因。根据异常信息,断点到retrofit2.Retrofit.nextCallAdapter(Retrofit.java:272)处。
由于方法返回值类型定义为Observable,因此将关注点放到RxJava2CallAdapterFactory上。get方法处,其内部,通过判断returnType确定是否使用该Factory创建CallAdapter
此时问题,在于接口定义的返回值为rx.Observable,而get方法内部判断使用的Observable为io.reactivex.Observable。从而完美的错过了这个Factory。
解决方法
通过上述分析得知,Retrofit请求接口的返回值,若定义为 Observable,该类型需为io.reactivex.Observable,于是,接口定义修改如下所示
interface NacosOperatorFunc {
@POST("auth/users/login")
Observable<Map<String, Object>> nacosLogin(@Query("username") String username, @Query("password") String password);
@GET("console/server/state")
Observable<Map<String, Object>> nacosVersion(@Query("accessToken") String accessToken, @Query("username") String userName);
}
此时Observable为io.reactivex.Observable。
再次执行test方法,成功获取请求结果
后记
特此记录该异常解决信息,用于提醒自己,后续查阅相关资料时,要确定其所使用的类,避免浪费时间在不应该出现的问题上。