-
-
Save krzysztof-miemiec/d6b6449b0e0e56e4a57e4ed7bc367aab to your computer and use it in GitHub Desktop.
| /** | |
| * Sample class showing how to use type converter in this gist. | |
| * | |
| * @author Krzysztof Miemiec | |
| */ | |
| @JsonObject | |
| public class Album extends RealmObject { | |
| @PrimaryKey | |
| @JsonField | |
| private String id; | |
| @JsonField(typeConverter = StringRealmListConverter.class) | |
| private RealmList<RealmString> imageUrls; | |
| public RealmList<RealmString> getImageUrls() { | |
| return imageUrls; | |
| } | |
| public void setImageUrls(RealmList<RealmString> imageUrls) { | |
| this.imageUrls = imageUrls; | |
| } | |
| } |
| /** | |
| * The universal converter for RealmList. | |
| * You can use this with RealmObjects: | |
| * 1. Annotated with @JsonObject | |
| * 2. With custom converters, such as RealmString below. | |
| * @author Krzysztof Miemiec | |
| */ | |
| public class RealmListConverter<T extends RealmObject> implements TypeConverter<RealmList<T>> { | |
| /** | |
| * This is useful if you want to use this converter for sending just a simple part of object back to server. | |
| * For example: | |
| * Server gives you this: | |
| * [{"id": 1, "description": "Doxie!", "image": "http://imgur.com/r/Dachshund/OGKuGTR"}, | |
| * {"id": 33, "description": "Second doxie!", "image": "http://imgur.com/r/Dachshund/nU3PlyO"}] | |
| * You send back: | |
| * [1, 33] | |
| */ | |
| public interface SingleFieldSerialization<T> { | |
| Object getValue(T object); | |
| } | |
| private Class<T> clazz; | |
| private TypeConverter<T> typeConverter; | |
| private JsonMapper<T> mapper; | |
| private SingleFieldSerialization<T> serializer; | |
| public RealmListConverter(Class<T> clazz) { | |
| this.clazz = clazz; | |
| } | |
| public RealmListConverter(Class<T> clazz, SingleFieldSerialization<T> serializer){ | |
| this.clazz = clazz; | |
| this.serializer = serializer; | |
| } | |
| private void init() { | |
| if (typeConverter == null && mapper == null) { | |
| try { | |
| typeConverter = LoganSquare.typeConverterFor(clazz); | |
| } catch (NoSuchTypeConverterException e) { | |
| mapper = LoganSquare.mapperFor(clazz); | |
| } | |
| } | |
| } | |
| @Override | |
| public RealmList<T> parse(JsonParser jsonParser) throws IOException { | |
| init(); | |
| RealmList<T> list = new RealmList<>(); | |
| if (jsonParser.getCurrentToken() == JsonToken.START_ARRAY) { | |
| while (jsonParser.nextToken() != JsonToken.END_ARRAY) { | |
| T object = typeConverter != null ? typeConverter.parse(jsonParser) : mapper.parse(jsonParser); | |
| if (object != null) { | |
| list.add(object); | |
| } | |
| } | |
| } | |
| return list; | |
| } | |
| @Override | |
| public void serialize(RealmList<T> list, String fieldName, boolean writeFieldNameForObject, JsonGenerator jsonGenerator) throws IOException { | |
| if (writeFieldNameForObject) { | |
| if (list == null) { | |
| return; | |
| } | |
| jsonGenerator.writeFieldName(fieldName); | |
| } | |
| if (list == null) { | |
| jsonGenerator.writeNull(); | |
| return; | |
| } | |
| jsonGenerator.writeStartArray(); | |
| if (serializer != null) { | |
| JsonMapper<Object> objectMapper = LoganSquare.mapperFor(Object.class); | |
| for (T object : list) { | |
| if (object != null) { | |
| objectMapper.serialize(serializer.getValue(object), jsonGenerator, true); | |
| } else { | |
| jsonGenerator.writeNull(); | |
| } | |
| } | |
| } else { | |
| init(); | |
| for (T object : list) { | |
| if (object != null) { | |
| if (typeConverter != null) { | |
| typeConverter.serialize(object, fieldName, false, jsonGenerator); | |
| } else { | |
| mapper.serialize(object, jsonGenerator, true); | |
| } | |
| } else { | |
| jsonGenerator.writeNull(); | |
| } | |
| } | |
| } | |
| jsonGenerator.writeEndArray(); | |
| } | |
| } |
| /** | |
| * A wrapper for holding Strings in RealmList. Shame. | |
| * | |
| * @author Krzysztof Miemiec | |
| */ | |
| public class RealmString extends RealmObject { | |
| public RealmString(String string) { | |
| this.string = string; | |
| } | |
| public RealmString() { | |
| } | |
| private String string; | |
| public String getString() { | |
| return string; | |
| } | |
| public void setString(String string) { | |
| this.string = string; | |
| } | |
| } |
| /** | |
| * A simple converter for RealmString wrapper. | |
| * | |
| * @author Krzysztof Miemiec | |
| */ | |
| public class RealmStringConverter extends StringBasedTypeConverter<RealmString> { | |
| @Override | |
| public RealmString getFromString(String string) { | |
| return new RealmString(string); | |
| } | |
| @Override | |
| public String convertToString(RealmString realmString) { | |
| return realmString.getString(); | |
| } | |
| } |
| /** | |
| * All you need to serialize/deserialize RealmList of RealmStrings. | |
| * It can be used thanks to that line: | |
| * LoganSquare.registerTypeConverter(RealmString.class, new RealmStringConverter()); | |
| * Put it in place where you initialize LoganSquare. | |
| * | |
| * @author Krzysztof Miemiec | |
| */ | |
| public class StringRealmListConverter extends RealmListConverter<RealmString> { | |
| public StringRealmListConverter() { | |
| super(RealmString.class); | |
| } | |
| } |
@peterbetos Your solution gives me this error: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Class.getCanonicalName()' on a null object reference
@Vinvent-Loi: look here https://gist.github.com/meierjan/36c885d76f1fda768837a27ea946eca3
@peterbetos, @Vincent-Loi, @meierjan: Unfortunately I haven't found any way to get rid of converters extending RealmListConverter<T>. For each type I had to create corresponding RealmListConverter.
Another solution (time-consuming one, but profitable for community that uses both LoganSquare & Realm) is to create a fork of LoganSquare that depends on Realm and generates code that does all of the above without any custom Type Converters.
Whoops, sorry forgot about this. I solved mine using the ParameterizedType implementation. You can refer to my implementation below:
https://gist.github.com/peterbetos/fb42ac87c31accd2efc43e33ddaaecc3
But yeah, @krzysztof-miemiec, no solution so far regarding the extensions.
Unless.... someone will do annotation processing for it? :D
Here's what I did (this is to prevent an additional constructor):