Определение типа аргумента в заданном FutureRequest
Скажем, у меня есть этот API, который:
- требует много вещей аутентификации.
- всегда возвращает 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);
}
Это прекрасно работает, пока мне не нужно получить запрос, чтобы вместо того, чтобы быть 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)'; оба метода имеют одинаковое стирание
Похоже, что эти типы были урезаны во время выполнения и ВМ запуталась.
Я придумал несколько "решений":
- Я мог бы использовать
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 ответа
Вместо 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
}
});
Вы можете использовать универсальный тип для передачи обоих 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);