【问题标题】:Detecting argument type in given FutureRequest检测给定 FutureRequest 中的参数类型
【发布时间】:2013-12-10 20:36:42
【问题描述】:

假设我有这个 API:

  1. 需要很多身份验证。
  2. 总是返回 JSON,但有时返回一个对象,有时返回一个数组。但是,很容易预测会返回什么。

我想用这个超级棒的Ion libraryKoushik 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);
}

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

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 而不声明类型,但是我需要它们在#18th 行。
  • 我可以改用String,然后用Gson解析它,
  • 我可以使用另一个参数来指定类型,然后将我的callback 转换为FutureRequest&lt;JsonObject&gt;FutureRequest&lt;JsonArray&gt;

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

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

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
    }
});

【问题讨论】:

    标签: java android api gson ion-koush


    【解决方案1】:

    而不是FutureCallback&lt;JsonObject&gt;FutureCallback&lt;JsonArray&gt;,为什么不像这样扩展它们:

    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
        }
    });
    

    【讨论】:

      【解决方案2】:

      您可以使用泛型类型将FutureCallback&lt;JsonObject&gt;FutureCallback&lt;JsonArray&gt; 作为参数传递给同一方法。

      您还需要知道 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-14
        • 1970-01-01
        • 1970-01-01
        • 2015-10-24
        • 1970-01-01
        • 1970-01-01
        • 2012-03-13
        相关资源
        最近更新 更多