【问题标题】:Return OkHttp Asynchronous result has some problem返回 OkHttp 异步结果有问题
【发布时间】:2019-07-22 13:29:02
【问题描述】:

我有一个javaSDK,它使用OkHttp客户端(4.0.0)从IAM服务器获取令牌并将令牌返回给应用程序。关系可能是这样的:Applicaiton同步调用SDKSDK异步调用IAM。参考这个答案Java - Retrieving Result from OkHttp Asynchronous GET,代码如下:

异步类:

class BaseAsyncResult<T> {
private final CompletableFuture<T> future = new CompletableFuture<>();

T getResult() {
    try {
        return future.get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return null;
}

void onFailure(IOException e) {
    future.completeExceptionally(e);
}

void onResponse(Response response) throws IOException {
    String bodyString = Objects.requireNonNull(response.body()).string();
    future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<T>() {}));
}
}

Okhttp 调用如下:

public void invoke(Request request, BaseAsyncResult result) {
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                result.onFailure(e);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                result.onResponse(response);
            }
        });
    }

应用程序使用 sdk 代码,iasClient 是 okhttp 客户端的包装器:

 BaseAsyncResult<AuthenticationResponse> iasAsyncResult = new BaseAsyncResult();
 iasClient.invoke(request, iasAsyncResult);
 AuthenticationResponse result = iasAsyncResult.getResult();

错误信息:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to x.x.x.AuthenticationResponse

我错过了什么?

【问题讨论】:

  • @Arpan Kanthal 的一个方法是向 BaseAsyncResult 添加一个私有 Class 类型变量,然后在 json2Pojo 函数中使用该类,然后 BaseAsyncResult 可能如下所示:

标签: java okhttp okhttp3


【解决方案1】:

您需要确保 jackson 知道要将值反序列化到哪个类。在这种情况下,您要求 Jackson 反序列化对 TypeReference 的响应,默认情况下它将解析为 Map ,除非您指定类(在本例中为 AuthenticationResponse )。由于这个原因,Future 解析为 linkedHashMap 并导致类强制转换。 尝试替换下面的行。

future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<T>() {}));

future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<AuthenticationResponse>() {}));

【讨论】:

  • 非常感谢,按照你的方法我改了代码就好了。但是我想BaseAsyncResult可以支持其他类型,可以吗?
  • @TongChen 你可以做两件事。一种是在 BaseAsyncResult 中传递结果类的类型。添加一个私有 Class 类型变量,然后在 json2Pojo 函数中使用该类。第二种解决方案是将结果转换为地图,然后将地图转换为 pojo,最终 MyPojo pojo = mapper.convertValue(map, MyPojo.class)
【解决方案2】:

@Arpan Kanthal 的一个方法是向 BaseAsyncResult 添加一个私有 Class 类型变量,然后在您的 json2Pojo 函数中使用该类,然后 BaseAsyncResult 可能是这样的:

public class BaseAsyncResult<T> {
    private final CompletableFuture<T> future = new CompletableFuture<>();
    private Class<T> classType;

    public BaseAsyncResult(Class<T> classType) {
        this.classType = classType;
    }

    public T getResult() {
        try {
            return future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }

    void onFailure(IOException e) {
        future.completeExceptionally(e);
    }

    void onResponse(Response response) throws IOException {
        future.complete(JacksonUtil.json2Pojo(response.body().string(), classType));
    }
}

【讨论】:

    猜你喜欢
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 2017-07-07
    • 1970-01-01
    相关资源
    最近更新 更多