Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The wonders you can do with Moshi

The wonders you can do with Moshi

Moshi is as very powerful and yet lightweight modern JSON library for Android and Java. It understands primitives and objects, Strings and enums, arrays and java’s build-int collections (such as Lists, Sets and Maps), at the same time providing a nice api for serialization/deserialization customization.

These slide are for my BarCamp Talk at DroidconUK 2016.
Include:
- Short intro to square/moshi
- Example for a complex custom adapter
- Reference to Moshi-Auto-Value & Moshi-Lazy-Adapters

Serj Lotutovici

October 28, 2016
Tweet

More Decks by Serj Lotutovici

Other Decks in Programming

Transcript

  1. Some  specs • JSON  serialisation/de-­‐serialisation   • Based  on  Okio

      ➡ Works  with  Source/Sink  not  java.io.*Stream   ➡ Avoids  unnecessary  buffering   • JsonReader/JsonWriter   • JsonAdapter
  2. JsonAdapter abstract T fromJson(JsonReader reader) throws IOException; abstract void toJson(JsonWriter

    writer, T value) throws IOException; @FromJson - Any method that accepts an object / JsonReader @ToJson - Any method that accepts an Object / JsonWriter
  3. JsonAdapter.Factory public interface Factory { JsonAdapter<?> create(Type type, Set<? extends

    Annotation> annotations, Moshi moshi); } • Called by Moshi#nextAdapter() • All JsonAdapter’s are retrieved via their respective factories! • Order matters!
  4. So  what? { "response": { "pokemon": [ { "name": "Pikachu",

    "weight": 3.45, "stats": {}, "is_buddy": true } ] } }
  5. @JsonQualifier  to  the  rescue • Allows to annotate a custom

    annotation that will be backed by a JsonAdapter. • Custom Annotations should be used for fields/methods/params ➡ Moshi doesn’t search for type annotations! • The adapters factory much check for the presents of the annotation • or, it should be used in a @FromJson/@ToJson annotated method
  6. So  let’s  fix  it @Documented
 @JsonQualifier
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ ElementType.FIELD, ElementType.METHOD,

    ElementType.PARAMETER })
 public @interface Wrapped {
 /** The path to the wrapped json value. */
 String[] value();
 }
  7. So  let’s  fix  it public static final JsonAdapter.Factory FACTORY =

    (type, annotations, moshi) -> {
 Annotation annotation = findAnnotation(annotations, Wrapped.class);
 if (annotation == null) return null;
 
 Set<? extends Annotation> reducedAnnotations = new LinkedHashSet<>(annotations);
 reducedAnnotations.remove(annotation);
 
 Wrapped wrapped = (Wrapped) annotation;
 return new WrappedJsonAdapter<>(moshi.adapter(type, reducedAnnotations), wrapped.value()); };
  8. So  what? { "response": { "pokemon": [ { "name": "Pikachu",

    "weight": 3.45, "stats": {}, "is_buddy": true } ] } }
  9. So  let’s  fix  it @Override public T fromJson(JsonReader reader) throws

    IOException {
 List<T> fromJson = adapter.fromJson(reader);
 if (fromJson != null && !fromJson.isEmpty()) return fromJson.get(0);
 return null;
 }
 
 @Override public void toJson(JsonWriter writer, T value) throws IOException {
 adapter.toJson(writer, Collections.singletonList(value));
 }
  10. Good  to  Know’s • Auto-­‐Value-­‐Moshi     https://github.com/rharter/auto-­‐value-­‐moshi   •

    Moshi-­‐Lazy-­‐Adapters   https://github.com/serj-­‐lotutovici/moshi-­‐lazy-­‐adapters