Skip to content

Instantly share code, notes, and snippets.

@varunachar
Last active February 25, 2020 01:17
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save varunachar/e98a2c240eddc56053c5 to your computer and use it in GitHub Desktop.
Save varunachar/e98a2c240eddc56053c5 to your computer and use it in GitHub Desktop.
Google Gson TypeAdapterFactory to use with Retrofit when the the object is nested inside another object (Typically an object which contains status code etc) and when the root changes per object like shown below in the sample ANestedObject.json. Then you can use Retrofit normally! Enjoy
// Root is hotel
{
status : "ok",
statusCode : 200,
hotels : [{
name : "Taj Palace",
location : {
lat : 12
lng : 77
}
}, {
name : "Plaza",
location : {
lat : 12
lng : 77
}
}]
}
//Root is city
{
status : "ok",
statusCode : 200,
city : {
name : "Bengaluru",
location : {
lat : 12
lng : 77
}
}
package com.example.api;
import com.example.pojo.Hotel;
import com.example.pojo.City;
import java.util.List;
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.POST;
import retrofit.http.Path;
import retrofit.http.Query;
import rx.Observable;
/**
* Created by varunachar on 20/11/15.
*/
public interface ApiService {
@GET("api/{id}")
Observable<City> city(@Path("id") String id);
@POST("hotel/nearby")
Observable<List<Hotel>> drivers(@Body Location location);
}
package com.example.pojos;
import com.example.pojos.Location;
import com.example.adapters.InnerKey;
@InnerKey("hotel")
public class Hotel {
private String name;
private Location location;
// getters, setters, other properties
}
package com.example.adapters;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by varunachar on 20/11/15.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InnerKey {
String value();
}
package com.example.adapters;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
/**
* Created by varunachar on 20/11/15.
*/
public class ItemTypeAdapter<T> extends TypeAdapter<T> {
private final String root;
private TypeAdapter<T> delegate;
private boolean isList = false;
public ItemTypeAdapter(String root, TypeAdapter<T> delegate, boolean isList) {
this.root = root;
this.delegate = delegate;
this.isList = isList;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
T obj = null;
// If not the parent object
if(!in.getPath().equalsIgnoreCase("$")){
return delegate.read(in);
}
in.beginObject();
while (in.hasNext()) {
if (root.equalsIgnoreCase(in.nextName())) {
if (isList) {
obj = delegate.read(in);
} else {
obj = delegate.read(in);
}
}
else {
in.skipValue();
}
}
in.endObject();
return obj;
}
}
package com.example.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.headlyt.adapters.TypeAdapterFactory;
import com.headlyt.utils.ApiConstants;
import com.headlyt.utils.CommonMethods;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import retrofit.GsonConverterFactory;
import retrofit.Retrofit;
import retrofit.RxJavaCallAdapterFactory;
/**
* Created by varunachar on 20/11/15.
*/
public class RestClient
{
private ApiService apiService;
private static RestClient restClient = new RestClient();
public static RestClient get() {
return restClient;
}
private RestClient()
{
Gson gson = new GsonBuilder()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
.registerTypeAdapterFactory(new TypeAdapterFactory())
.create();
OkHttpClient client = new OkHttpClient();
client.interceptors().add(chain -> {
Request request = chain.request();
HttpUrl url = request.httpUrl().newBuilder().addQueryParameter("access_token", CommonMethods.getAccessToken()).build();
request = request.newBuilder().url(url).build();
return chain.proceed(request);
});
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConstants.API_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(client)
.build();
apiService = retrofit.create(ApiService.class);
}
public ApiService api()
{
return apiService;
}
}
package com.example.adapters;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.ParameterizedType;
import java.util.List;
/**
* Created by varunachar on 20/11/15.
*/
public class TypeAdapterFactory implements com.google.gson.TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(final Gson gson, TypeToken<T> type) {
TypeAdapter<T> adapter = gson.getDelegateAdapter(this, type);
if (type.getRawType().isAssignableFrom(List.class)) {
ParameterizedType parameterizedType = (ParameterizedType) type.getType();
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(parameterizedType.getActualTypeArguments()[0]);
TypeAdapter<T> elementAdapter = gson.getAdapter(typeToken);
if (typeToken.getRawType().isAnnotationPresent(InnerKey.class)) {
return new ItemTypeAdapter<>(typeToken.getRawType().getAnnotation(InnerKey.class).value().concat("s"), adapter, true);
} else {
return adapter;
}
} else {
if (!type.getRawType().isAnnotationPresent(InnerKey.class)) {
return adapter;
}
return new ItemTypeAdapter<>(type.getRawType().getAnnotation(InnerKey.class).value(), adapter, false);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment