1 /* 2 * Copyright (C) 2017 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.squareup.moshi.recipes; 17 18 import static java.lang.annotation.RetentionPolicy.RUNTIME; 19 20 import com.squareup.moshi.JsonAdapter; 21 import com.squareup.moshi.JsonQualifier; 22 import com.squareup.moshi.JsonReader; 23 import com.squareup.moshi.JsonWriter; 24 import com.squareup.moshi.Moshi; 25 import com.squareup.moshi.Types; 26 import com.squareup.moshi.recipes.Unwrap.EnvelopeJsonAdapter.Enveloped; 27 import com.squareup.moshi.recipes.models.Card; 28 import java.io.IOException; 29 import java.lang.annotation.Annotation; 30 import java.lang.annotation.Retention; 31 import java.lang.reflect.Type; 32 import java.util.Set; 33 import javax.annotation.Nullable; 34 35 final class Unwrap { Unwrap()36 private Unwrap() {} 37 main(String[] args)38 public static void main(String[] args) throws Exception { 39 String json = 40 "" 41 + "{\"data\":" 42 + " {\n" 43 + " \"rank\": \"4\",\n" 44 + " \"suit\": \"CLUBS\"\n" 45 + " }" 46 + "}"; 47 Moshi moshi = new Moshi.Builder().add(EnvelopeJsonAdapter.FACTORY).build(); 48 JsonAdapter<Card> adapter = moshi.adapter(Card.class, Enveloped.class); 49 Card out = adapter.fromJson(json); 50 System.out.println(out); 51 } 52 53 public static final class EnvelopeJsonAdapter extends JsonAdapter<Object> { 54 public static final JsonAdapter.Factory FACTORY = 55 new Factory() { 56 @Override 57 public @Nullable JsonAdapter<?> create( 58 Type type, Set<? extends Annotation> annotations, Moshi moshi) { 59 Set<? extends Annotation> delegateAnnotations = 60 Types.nextAnnotations(annotations, Enveloped.class); 61 if (delegateAnnotations == null) { 62 return null; 63 } 64 Type envelope = 65 Types.newParameterizedTypeWithOwner( 66 EnvelopeJsonAdapter.class, Envelope.class, type); 67 JsonAdapter<Envelope<?>> delegate = 68 moshi.nextAdapter(this, envelope, delegateAnnotations); 69 return new EnvelopeJsonAdapter(delegate); 70 } 71 }; 72 73 @Retention(RUNTIME) 74 @JsonQualifier 75 public @interface Enveloped {} 76 77 private static final class Envelope<T> { 78 final T data; 79 Envelope(T data)80 Envelope(T data) { 81 this.data = data; 82 } 83 } 84 85 private final JsonAdapter<Envelope<?>> delegate; 86 EnvelopeJsonAdapter(JsonAdapter<Envelope<?>> delegate)87 EnvelopeJsonAdapter(JsonAdapter<Envelope<?>> delegate) { 88 this.delegate = delegate; 89 } 90 91 @Override fromJson(JsonReader reader)92 public Object fromJson(JsonReader reader) throws IOException { 93 return delegate.fromJson(reader).data; 94 } 95 96 @Override toJson(JsonWriter writer, Object value)97 public void toJson(JsonWriter writer, Object value) throws IOException { 98 delegate.toJson(writer, new Envelope<>(value)); 99 } 100 } 101 } 102