Last active
April 15, 2016 15:25
-
-
Save Gregadeaux/cbcc3781fda9d7fa6498 to your computer and use it in GitHub Desktop.
JSONAPI Converter for RetroFit with RxJava and RetroLambda
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Good call. This was built using retrolamda.