1 /* 2 * Copyright (C) 2011 Google 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 * http://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 17 package com.google.gson.internal.bind; 18 19 import com.google.gson.Gson; 20 import com.google.gson.JsonDeserializationContext; 21 import com.google.gson.JsonDeserializer; 22 import com.google.gson.JsonElement; 23 import com.google.gson.JsonParseException; 24 import com.google.gson.JsonSerializationContext; 25 import com.google.gson.JsonSerializer; 26 import com.google.gson.TypeAdapter; 27 import com.google.gson.TypeAdapterFactory; 28 import com.google.gson.internal.$Gson$Preconditions; 29 import com.google.gson.internal.Streams; 30 import com.google.gson.reflect.TypeToken; 31 import com.google.gson.stream.JsonReader; 32 import com.google.gson.stream.JsonWriter; 33 import java.io.IOException; 34 import java.lang.reflect.Type; 35 36 /** 37 * Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the 38 * tree adapter may be serialization-only or deserialization-only, this class 39 * has a facility to lookup a delegate type adapter on demand. 40 */ 41 public final class TreeTypeAdapter<T> extends SerializationDelegatingTypeAdapter<T> { 42 private final JsonSerializer<T> serializer; 43 private final JsonDeserializer<T> deserializer; 44 final Gson gson; 45 private final TypeToken<T> typeToken; 46 private final TypeAdapterFactory skipPast; 47 private final GsonContextImpl context = new GsonContextImpl(); 48 private final boolean nullSafe; 49 50 /** The delegate is lazily created because it may not be needed, and creating it may fail. */ 51 private volatile TypeAdapter<T> delegate; 52 TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast, boolean nullSafe)53 public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, 54 Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast, boolean nullSafe) { 55 this.serializer = serializer; 56 this.deserializer = deserializer; 57 this.gson = gson; 58 this.typeToken = typeToken; 59 this.skipPast = skipPast; 60 this.nullSafe = nullSafe; 61 } 62 TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast)63 public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, 64 Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) { 65 this(serializer, deserializer, gson, typeToken, skipPast, true); 66 } 67 read(JsonReader in)68 @Override public T read(JsonReader in) throws IOException { 69 if (deserializer == null) { 70 return delegate().read(in); 71 } 72 JsonElement value = Streams.parse(in); 73 if (nullSafe && value.isJsonNull()) { 74 return null; 75 } 76 return deserializer.deserialize(value, typeToken.getType(), context); 77 } 78 write(JsonWriter out, T value)79 @Override public void write(JsonWriter out, T value) throws IOException { 80 if (serializer == null) { 81 delegate().write(out, value); 82 return; 83 } 84 if (nullSafe && value == null) { 85 out.nullValue(); 86 return; 87 } 88 JsonElement tree = serializer.serialize(value, typeToken.getType(), context); 89 Streams.write(tree, out); 90 } 91 delegate()92 private TypeAdapter<T> delegate() { 93 // A race might lead to `delegate` being assigned by multiple threads but the last assignment will stick 94 TypeAdapter<T> d = delegate; 95 return d != null 96 ? d 97 : (delegate = gson.getDelegateAdapter(skipPast, typeToken)); 98 } 99 100 /** 101 * Returns the type adapter which is used for serialization. Returns {@code this} 102 * if this {@code TreeTypeAdapter} has a {@link #serializer}; otherwise returns 103 * the delegate. 104 */ getSerializationDelegate()105 @Override public TypeAdapter<T> getSerializationDelegate() { 106 return serializer != null ? this : delegate(); 107 } 108 109 /** 110 * Returns a new factory that will match each type against {@code exactType}. 111 */ newFactory(TypeToken<?> exactType, Object typeAdapter)112 public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) { 113 return new SingleTypeFactory(typeAdapter, exactType, false, null); 114 } 115 116 /** 117 * Returns a new factory that will match each type and its raw type against 118 * {@code exactType}. 119 */ newFactoryWithMatchRawType( TypeToken<?> exactType, Object typeAdapter)120 public static TypeAdapterFactory newFactoryWithMatchRawType( 121 TypeToken<?> exactType, Object typeAdapter) { 122 // only bother matching raw types if exact type is a raw type 123 boolean matchRawType = exactType.getType() == exactType.getRawType(); 124 return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null); 125 } 126 127 /** 128 * Returns a new factory that will match each type's raw type for assignability 129 * to {@code hierarchyType}. 130 */ newTypeHierarchyFactory( Class<?> hierarchyType, Object typeAdapter)131 public static TypeAdapterFactory newTypeHierarchyFactory( 132 Class<?> hierarchyType, Object typeAdapter) { 133 return new SingleTypeFactory(typeAdapter, null, false, hierarchyType); 134 } 135 136 private static final class SingleTypeFactory implements TypeAdapterFactory { 137 private final TypeToken<?> exactType; 138 private final boolean matchRawType; 139 private final Class<?> hierarchyType; 140 private final JsonSerializer<?> serializer; 141 private final JsonDeserializer<?> deserializer; 142 SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, Class<?> hierarchyType)143 SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, 144 Class<?> hierarchyType) { 145 serializer = typeAdapter instanceof JsonSerializer 146 ? (JsonSerializer<?>) typeAdapter 147 : null; 148 deserializer = typeAdapter instanceof JsonDeserializer 149 ? (JsonDeserializer<?>) typeAdapter 150 : null; 151 $Gson$Preconditions.checkArgument(serializer != null || deserializer != null); 152 this.exactType = exactType; 153 this.matchRawType = matchRawType; 154 this.hierarchyType = hierarchyType; 155 } 156 157 @SuppressWarnings("unchecked") // guarded by typeToken.equals() call 158 @Override create(Gson gson, TypeToken<T> type)159 public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 160 boolean matches = exactType != null 161 ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() 162 : hierarchyType.isAssignableFrom(type.getRawType()); 163 return matches 164 ? new TreeTypeAdapter<>((JsonSerializer<T>) serializer, 165 (JsonDeserializer<T>) deserializer, gson, type, this) 166 : null; 167 } 168 } 169 170 private final class GsonContextImpl implements JsonSerializationContext, JsonDeserializationContext { serialize(Object src)171 @Override public JsonElement serialize(Object src) { 172 return gson.toJsonTree(src); 173 } serialize(Object src, Type typeOfSrc)174 @Override public JsonElement serialize(Object src, Type typeOfSrc) { 175 return gson.toJsonTree(src, typeOfSrc); 176 } 177 @SuppressWarnings("unchecked") deserialize(JsonElement json, Type typeOfT)178 @Override public <R> R deserialize(JsonElement json, Type typeOfT) throws JsonParseException { 179 return gson.fromJson(json, typeOfT); 180 } 181 } 182 } 183