Skip to content

Instantly share code, notes, and snippets.

@Gregadeaux
Last active April 15, 2016 15:25
Show Gist options
  • Save Gregadeaux/cbcc3781fda9d7fa6498 to your computer and use it in GitHub Desktop.
Save Gregadeaux/cbcc3781fda9d7fa6498 to your computer and use it in GitHub Desktop.
JSONAPI Converter for RetroFit with RxJava and RetroLambda
package ai.cometandroid.network;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.LinkedHashTreeMap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import ai.cometandroid.models.JsonApiResponse;
import retrofit.converter.ConversionException;
import retrofit.converter.Converter;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;
import rx.Observable;
/**
* Created by greg on 6/26/15.
*/
public class JsonApiConverter implements Converter {
private static String RELATIONSHIP_KEY = "relationships";
private static String ATTRIBUTES_KEY = "attributes";
@Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
try {
InputStream in = body.in();
String json = fromJsonApi(fromStream(in));
if(String.class.equals(type)) return json;
else return new Gson().fromJson(json, type);
} catch (Exception e) {
throw new ConversionException(e);
}
}
@Override
public TypedOutput toBody(Object object) {
try {
Map<String, Object> jsonApi = new LinkedHashTreeMap<>();
jsonApi.put("data", object);
return new JsonTypedOutput(new Gson().toJson(jsonApi).getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
}
private static class JsonTypedOutput implements TypedOutput {
private final byte[] jsonBytes;
JsonTypedOutput(byte[] jsonBytes) { this.jsonBytes = jsonBytes; }
@Override public String fileName() { return null; }
@Override public String mimeType() { return "application/json; charset=UTF-8"; }
@Override public long length() { return jsonBytes.length; }
@Override public void writeTo(OutputStream out) throws IOException { out.write(jsonBytes); }
}
private static String fromStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append("\r\n");
}
return out.toString();
}
private static String fromJsonApi(String json) throws Exception {
Gson gson = new Gson();
JsonApiResponse response = gson.fromJson(json, JsonApiResponse.class);
List<Map<String, Object>> data = new ArrayList<>();
response.data()
.doOnNext(stringObjectMap -> {
stringObjectMap.putAll((Map<String, Object>) stringObjectMap.get(ATTRIBUTES_KEY));
stringObjectMap.remove(ATTRIBUTES_KEY);
Observable.from(((Map<String, Object>) stringObjectMap.get(RELATIONSHIP_KEY)).keySet())
.filter(key -> ((Map<String, Object>) stringObjectMap.get(RELATIONSHIP_KEY)).get(key) instanceof Map || ((Map<String, Object>) stringObjectMap.get(RELATIONSHIP_KEY)).get(key) instanceof List)
.subscribe(key -> {
stringObjectMap.put(key, ((Map<String, Object>) ((Map<String, Object>) stringObjectMap.get(RELATIONSHIP_KEY)).get(key)).get("data"));
Observable<Map<String, Object>> inner;
Object includedLinks = stringObjectMap.get(key);
if (includedLinks instanceof List) inner = Observable.from((List<Map<String, Object>>) includedLinks);
else inner = Observable.just((Map<String, Object>) includedLinks);
inner.forEach(link -> response.included()
.filter(included -> included.get("type").equals(link.get("type")) && included.get("id").equals(link.get("id")))
.first()
.subscribe(included -> link.putAll((Map<String, Object>) included.get(ATTRIBUTES_KEY))));
});
stringObjectMap.remove(RELATIONSHIP_KEY);
})
.subscribe(datum -> data.add(datum));
String formatted;
if(data.size() == 1) {
formatted = gson.toJson(data.get(0));
}else {
formatted = gson.toJson(data);
}
return formatted;
}
}
package ai.cometandroid.models;
import java.util.List;
import java.util.Map;
import rx.Observable;
/**
* Created by greg on 6/26/15.
*/
public class JsonApiResponse {
private Object data;
private List<Map<String, Object>> included;
private Map<String, Object> meta;
private Map<String, Object> links;
public Observable<Map<String, Object>> included() {
return Observable.from(included);
}
public Observable<Map<String, Object>> data() {
if(data instanceof List) return Observable.from((List<Map<String,Object>>)data);
else return Observable.just((Map<String,Object>)data);
}
}
@Gregadeaux
Copy link
Author

Good call. This was built using retrolamda.

@tagrudev
Copy link

@Gregadeaux how would you implement this for retrofit2 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment