-
-
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); | |
} | |
} |
When I tried a default constructor, it shows this error:
Class io.realm.UserRealmProxy could not be mapped to a JSON object. Perhaps it hasn't been annotated with @JsonObject?
Here's what I did (this is to prevent an additional constructor):
Class<T> clazz;
TypeConverter<T> typeConverter;
JsonMapper<T> mapper;
protected SingleFieldSerialization<T> singleFieldSerialization;
private void init() {
if (typeConverter == null && mapper == null) {
try {
typeConverter = LoganSquare.typeConverterFor(getPersistentClass());
} catch (NoSuchTypeConverterException e) {
mapper = LoganSquare.mapperFor(getPersistentClass());
}
}
}
public Class<T> getPersistentClass() {
if (clazz == null) {
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
return clazz;
}
@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
I'm getting an error "TypeConverter classes must have a non-private zero argument constructor."
Do you know if we need to add these default constructor?
public RealmListConverter(){
}