Say I have this API that:
And I want to use this super freaking awesome Ion library (by Koushik Dutta).
As the API I'm using, requires authentication, setting proper headers with every request, etc. I'm going to wrap it somehow, say: 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);
}
That works great until I need to receive a request that instead of being a JsonObject
is a JsonArray
:
java.lang.ClassCastException: com.google.gson.JsonArray cannot be cast to com.google.gson.JsonObject
So as a quick workaround I can create two methods that redirect flow to one common, but to make things easier here, say it looks like this: 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);
}
But then BAM, another error appears:
'sendRequest(String, JsonObject, FutureCallback)' clashes with 'sendRequest(String, JsonObject, FutureCallback)'; both methods have same erasure
Seems like those types got stripped down in runtime and VM gets confused.
I've come up with some "solutions":
FutureRequest
without declaring types at all, but then I need them in #18th line. String
instead, and then parse it with Gson
,callback
to either FutureRequest<JsonObject>
or FutureRequest<JsonArray>
But all of them seem to be only some cheap hacks to make things (somehow) work. Does anyone here know any proper solution to that problem?
My most preferred way of calling those methods would be:
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
}
});
Instead of FutureCallback<JsonObject>
and FutureCallback<JsonArray>
, why not extend these like this:
public interface JsonObjectFutureCallback extends FutureCallback<JsonObject> { }
public interface JsonArrayFutureCallback extends FutureCallback<JsonArray> { }
Then you can call your methods like so:
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
}
});