In retrofit to map json response to pojo usually we do this
@POST
Call getDataFromServer(@Url String url, @Body HashMap ha
I use following approach: First I have implemented custom Call
public class ProxyConvertCall implements Call {
Converter converter;
Call innerCall;
public ProxyConvertCall2(Call jcall, Converter converter){
this.innerCall = jcall;
this.converter = converter;
}
@Override
public Response execute() throws IOException {
Response response = innerCall.execute();
if (response.isSuccessful()){
return Response.success(converter.Convert(response.body()),response.raw());
}
else return Response.error(response.code(), response.errorBody());
}
@Override
public void enqueue(final Callback callback) {
final Call self = this;
this.innerCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()){
callback.onResponse(self, Response.success(converter.Convert(response.body()), response.raw()));
}
else callback.onResponse(self, Response.error(response.code(), response.errorBody()));
}
@Override
public void onFailure(Call call, Throwable t) {
callback.onFailure(self,t);
}
});
}
@Override
public boolean isExecuted() {
return innerCall.isExecuted();
}
@Override
public void cancel() {
innerCall.cancel();
}
@Override
public boolean isCanceled() {
return innerCall.isCanceled();
}
@Override
public Call clone() {
return new ProxyConvertCall2<>(innerCall,converter);
}
@Override
public Request request() {
return innerCall.request();
}
}
It wrappes Call and converts it's result to by converter.
@FunctionalInterface
public interface Converter {
public Tout Convert(Tin in);
}
For your service you must create service interface, that return JsonObject for single object and JsonArray for arrays
public interface ApiCalls {
@POST
Call getDataFromServer(@Url String url, @Body HashMap hashMap);
@POST
Call getArrayFromServer(@Url String url, @Body HashMap hashMap);
}
Then wrap it with generic class, with converters from JsonElement to any Type :
public class ApiCallsGeneric {
Converter fromJsonObject;
Converter> fromJsonArray;
ApiCalls service;
public ApiCallsGeneric(Class classOfT, ApiCalls service){
this.service = service;
Gson gson = new GsonBuilder().create();
GenericListType genericListTypeOfT = new GenericListType(classOfT);
fromJsonObject = (t)->gson.fromJson(t,classOfT);
fromJsonArray =(t)->gson.fromJson(t,genericListTypeOfT);
}
public Call getDataFromServer(String url, HashMap hashMap){
return new ProxyConvertCall<>(service.getDataFromServer(url, hashMap), fromJsonObject);
}
public Call> getArrayFromServer(String url, HashMap hashMap){
return new ProxyConvertCall<>(service.getArrayFromServer(url, hashMap), fromJsonArray);
}
}
GenericListType is ParaterizedType. It is used for passing type parameter to gson for List
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
public class GenericListType implements ParameterizedType {
private Type wrapped;
public GenericListType(Type wrapped) {
this.wrapped = wrapped;
}
public Type[] getActualTypeArguments() {
return new Type[] {wrapped};
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return null;
}
}
Then you can instantiate ApiCallsGeneric with type you want.
ApiCallsGeneric userService= new ApiCallsGeneric(User.class, retrofit.create(ApiCalls.class));
Call call = userService.getDataFromServer(StringConstants.URL,hashMap);
call.enqueue(new Callback() {
//Response and failure callbacks
}