Created
August 27, 2017 02:29
-
-
Save genderquery/2c9f6afe95aad98cca3146851a56c582 to your computer and use it in GitHub Desktop.
SplitCollectionJsonAdapter
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
static class Layer { | |
int id; | |
@Split(delimiter = ",") List<Integer> childIds; | |
@Split(delimiter = ",") EnumSet<Format> supportedFormats; | |
} | |
static enum Format { | |
PNG, JPEG, TIFF | |
} | |
static { | |
Moshi moshi = new Moshi.Builder() | |
.add(SplitCollectionJsonAdapter.FACTORY) | |
.build(); | |
Layer layer = moshi.adapter(Layer.class).fromJson(json); | |
layer.childIds.contains(2); // true | |
layer.supportedFormats.contains(Format.PNG); // true | |
} |
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
{ | |
"id": 1, | |
"childIds": "2,3,4", | |
"supportedFormats": "PNG,JPEG" | |
} |
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 genderquery.github.com; | |
import com.squareup.moshi.JsonQualifier; | |
import java.lang.annotation.Documented; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.Target; | |
import static java.lang.annotation.ElementType.FIELD; | |
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |
/** | |
* Allows JSON values written as delimited lists. | |
*/ | |
@Target(FIELD) | |
@Retention(RUNTIME) | |
@JsonQualifier | |
@Documented | |
public @interface Split { | |
String delimiter(); | |
} |
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 genderquery.github.com; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import com.squareup.moshi.JsonAdapter; | |
import com.squareup.moshi.JsonReader; | |
import com.squareup.moshi.JsonWriter; | |
import com.squareup.moshi.Moshi; | |
import com.squareup.moshi.Types; | |
import java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Type; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.EnumSet; | |
import java.util.Iterator; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Set; | |
/** | |
* Converts delimited JSON strings to collection types, including {@link EnumSet}. | |
* <p> | |
* Use {@literal @Split} to annotate members. | |
*/ | |
public abstract class SplitCollectionJsonAdapter<C extends Collection<T>, T> | |
extends JsonAdapter<C> { | |
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() { | |
@Override | |
@Nullable | |
public JsonAdapter<?> create(@NonNull Type type, | |
@NonNull Set<? extends Annotation> annotations, | |
@NonNull Moshi moshi) { | |
Split annotation = (Split) getAnnotation(annotations, Split.class); | |
if (annotation == null) return null; | |
String delimiter = annotation.delimiter(); | |
Class<?> rawType = Types.getRawType(type); | |
if (rawType == List.class || rawType == Collection.class) { | |
return newArrayListAdapter(type, moshi, delimiter).nullSafe(); | |
} else if (rawType == Set.class) { | |
return newLinkedHashSetAdapter(type, moshi, delimiter).nullSafe(); | |
} else if (rawType == EnumSet.class) { | |
//noinspection unchecked | |
return newEnumSetAdapter(type, moshi, delimiter).nullSafe(); | |
} | |
return null; | |
} | |
}; | |
@Nullable | |
private static Annotation getAnnotation(Set<? extends Annotation> annotations, | |
Class<? extends Annotation> annotationClass) { | |
if (annotations.isEmpty()) return null; // Save an iterator in the common case. | |
for (Annotation annotation : annotations) { | |
if (annotation.annotationType() == annotationClass) return annotation; | |
} | |
return null; | |
} | |
private final JsonAdapter<T> elementAdapter; | |
private final String delimiter; | |
private SplitCollectionJsonAdapter(JsonAdapter<T> elementAdapter, String delimiter) { | |
this.elementAdapter = elementAdapter; | |
this.delimiter = delimiter; | |
} | |
private static <T> JsonAdapter<Collection<T>> newArrayListAdapter( | |
@NonNull Type type, @NonNull Moshi moshi, @NonNull String delimiter) { | |
Type elementType = Types.collectionElementType(type, Collection.class); | |
JsonAdapter<T> elementAdapter = moshi.adapter(elementType); | |
return new SplitCollectionJsonAdapter<Collection<T>, T>(elementAdapter, delimiter) { | |
@Override | |
Collection<T> newCollection() { | |
return new ArrayList<>(); | |
} | |
}; | |
} | |
private static <T> JsonAdapter<Set<T>> newLinkedHashSetAdapter( | |
@NonNull Type type, @NonNull Moshi moshi, @NonNull String delimiter) { | |
Type elementType = Types.collectionElementType(type, Collection.class); | |
JsonAdapter<T> elementAdapter = moshi.adapter(elementType); | |
return new SplitCollectionJsonAdapter<Set<T>, T>(elementAdapter, delimiter) { | |
@Override | |
Set<T> newCollection() { | |
return new LinkedHashSet<>(); | |
} | |
}; | |
} | |
private static <T extends Enum<T>> JsonAdapter<EnumSet<T>> newEnumSetAdapter( | |
@NonNull final Type type, @NonNull Moshi moshi, @NonNull String delimiter) { | |
final Type elementType = Types.collectionElementType(type, Collection.class); | |
JsonAdapter<T> elementAdapter = moshi.adapter(elementType); | |
return new SplitCollectionJsonAdapter<EnumSet<T>, T>(elementAdapter, delimiter) { | |
@Override | |
EnumSet<T> newCollection() { | |
//noinspection unchecked | |
return EnumSet.noneOf((Class<T>) elementType); | |
} | |
}; | |
} | |
abstract C newCollection(); | |
@Override | |
public C fromJson(@NonNull JsonReader reader) throws IOException { | |
C result = newCollection(); | |
String[] values = reader.nextString().split(delimiter); | |
for (String value : values) { | |
result.add(elementAdapter.fromJsonValue(value)); | |
} | |
return result; | |
} | |
@Override | |
public void toJson(@NonNull JsonWriter writer, C values) throws IOException { | |
StringBuilder result = new StringBuilder(); | |
Iterator<T> iterator = values.iterator(); | |
if (iterator.hasNext()) { | |
result.append(iterator.next()); | |
while (iterator.hasNext()) { | |
result.append(delimiter); | |
result.append(elementAdapter.toJsonValue(iterator.next())); | |
} | |
} | |
writer.value(result.toString()); | |
} | |
@Override | |
public String toString() { | |
return elementAdapter + ".collection()"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment