在给定的FutureRequest中检测参数类型

时间:2013-12-10 20:36:42

标签: java android api gson ion-koush

说我有这个API:

  1. 需要大量身份验证。
  2. 总是返回JSON,但有时候是一个对象,有时候是一个数组。但是,很容易预测将要返回的内容。
  3. 我想使用这个超级怪异的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);
    }
    

    这很有效,直到我需要收到JsonObject而不是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
    • 解析它
    • 我可以使用其他参数指定类型,然后将callback投射到FutureRequest<JsonObject>FutureRequest<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
        }
    });
    

2 个答案:

答案 0 :(得分:1)

而不是FutureCallback<JsonObject>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
    }
});

答案 1 :(得分: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);