3

假设我有这个 API:

  1. 需要很多认证的东西。
  2. 总是返回 JSON,但有时返回一个对象,有时返回一个数组。但是,很容易预测将返回什么。

我想使用这个超级棒的Ion 库(由Koushik Dutta 提供)。

作为我正在使用的 API,需要身份验证,为每个请求设置正确的标头等。我将以某种方式包装它,例如:http: //goo.gl/5NLeQn

private void sendRequest(String action, JsonObject params, FutureCallback<JsonObject> callback) {

  String nonce = "" + getNonce();

  Builders.Any.B req = Ion.with(context, BASE_URL + action);

  req.setBodyParameter("key", API_KEY)
    .setBodyParameter("signature", getSignature(nonce))
    .setBodyParameter("nonce", nonce);

  if( params!=null ) {
    for(Map.Entry<String, JsonElement> param : params.entrySet()) {
      JsonElement el = param.getValue();
      if( el.isJsonPrimitive() ) req.setBodyParameter(param.getKey(), el.getAsString());
    }
  }

  req.asJsonObject()
    .setCallback(callback);
}

这很好用,直到我需要收到一个请求,而不是 a JsonObjectis a JsonArray

java.lang.ClassCastException:com.google.gson.JsonArray 无法转换为 com.google.gson.JsonObject

因此,作为一种快速的解决方法,我可以创建两种将流程重定向到一个公共的方法,但为了让事情在这里更容易,说它看起来像这样:http: //goo.gl/pzSal3

private void sendRequest(String action, JsonObject params, FutureCallback<JsonObject> callback) {

  String nonce = "" + getNonce();

  Builders.Any.B req = Ion.with(context, BASE_URL + action);

  req.setBodyParameter("key", API_KEY)
    .setBodyParameter("signature", getSignature(nonce))
    .setBodyParameter("nonce", nonce);

  if( params!=null ) {
    for(Map.Entry<String, JsonElement> param : params.entrySet()) {
      JsonElement el = param.getValue();
      if( el.isJsonPrimitive() ) req.setBodyParameter(param.getKey(), el.getAsString());
    }
  }

  req.asJsonObject()
    .setCallback(callback);
}

private void sendRequest(String action, JsonObject params, FutureCallback<JsonArray> callback) {

  String nonce = "" + getNonce();

  Builders.Any.B req = Ion.with(context, BASE_URL + action);

  req.setBodyParameter("key", API_KEY)
    .setBodyParameter("signature", getSignature(nonce))
    .setBodyParameter("nonce", nonce);

  if( params!=null ) {
    for(Map.Entry<String, JsonElement> param : params.entrySet()) {
      JsonElement el = param.getValue();
      if( el.isJsonPrimitive() ) req.setBodyParameter(param.getKey(), el.getAsString());
    }
  }

  req.asJsonArray()
    .setCallback(callback);
}

但是然后BAM,又出现了一个错误:

'sendRequest(String, JsonObject, FutureCallback)' 与 'sendRequest(String, JsonObject, FutureCallback)' 发生冲突;两种方法都有相同的擦除

似乎这些类型在运行时被剥离并且VM变得混乱。

我想出了一些“解决方案”

  • 我可以FutureRequest在不声明类型的情况下使用,但是我需要它们在第 18 行。
  • 我可以String改用,然后用Gson,
  • 我可以使用另一个参数来指定类型,然后将 mycallback转换为FutureRequest<JsonObject>orFutureRequest<JsonArray>

但所有这些似乎都只是一些廉价的技巧,可以让事情(以某种方式)工作。这里有人知道该问题的任何适当解决方案吗?

我最喜欢的调用这些方法的方式是:

sendRequest(ACTION_BALANCE, null, new FutureRequest<JsonObject>() { 
    @Override
    public void onCompleted(Exception e, JsonObject result) {
        // my code goes here
    }
});

// OR just

sendRequest(ACTION_OPERATIONS, null, new FutureRequest<JsonArray>() { 
    @Override
    public void onCompleted(Exception e, JsonArray result) {
        // my code goes here
    }
});
4

2 回答 2

1

而不是FutureCallback<JsonObject>and FutureCallback<JsonArray>,为什么不像这样扩展这些:

public interface JsonObjectFutureCallback extends FutureCallback<JsonObject> { }
public interface JsonArrayFutureCallback extends FutureCallback<JsonArray> { }

然后你可以像这样调用你的方法:

sendRequest(ACTION_BALANCE, null, new JsonObjectFutureCallback() { 
    @Override
    public void onCompleted(Exception e, JsonObject result) {
        // my code goes here
    }
});

// OR just

sendRequest(ACTION_OPERATIONS, null, new JsonArrayFutureCallback() { 
    @Override
    public void onCompleted(Exception e, JsonArray result) {
        // my code goes here
    }
});
于 2013-12-11T20:22:53.863 回答
1

您可以使用泛型类型将两者都FutureCallback<JsonObject>作为FutureCallback<JsonArray>参数传递给同一个方法。

您还需要知道 T 的类型,以便调用适当的req.as(JsonObject/JsonArray)()方法。不幸的是,java泛型大多是编译时的,所以类型信息在运行时会丢失。您可以通过将额外的 Class 参数传递给您的方法来绕过它。

所以 sendRequest 方法应该是这样的:

private <T>void sendRequest(String action, JsonObject params, FutureCallback<T> callback, Class<?> type) {

    // body of the method

    if(type == JsonObject.class) {
        req.asJsonObject().setCallback(callback);
    }
    else if(type == JsonArray.class) {
        req.asJsonArray().setCallback(callback);
    }
}

你可以这样调用你的方法:

sendRequest(ACTION_BALANCE, null, new FutureRequest<JsonObject>() { 
    @Override
    public void onCompleted(Exception e, JsonObject result) {
       // my code goes here
    }
}, JsonObject.class);

// OR just

sendRequest(ACTION_OPERATIONS, null, new FutureRequest<JsonArray>() { 
    @Override
    public void onCompleted(Exception e, JsonArray result) {
        // my code goes here
    }
}, JsonArray.class);
于 2013-12-12T00:20:49.633 回答