/*
|
* Copyright (C) 2011 Google Inc.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
package cn.emay.sdk.util.json.gson;
|
|
import java.io.IOException;
|
|
import cn.emay.sdk.util.json.gson.internal.$Gson$Preconditions;
|
import cn.emay.sdk.util.json.gson.internal.Streams;
|
import cn.emay.sdk.util.json.gson.reflect.TypeToken;
|
import cn.emay.sdk.util.json.gson.stream.JsonReader;
|
import cn.emay.sdk.util.json.gson.stream.JsonWriter;
|
|
/**
|
* Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the
|
* tree adapter may be serialization-only or deserialization-only, this class
|
* has a facility to lookup a delegate type adapter on demand.
|
*/
|
final class TreeTypeAdapter<T> extends TypeAdapter<T> {
|
private final JsonSerializer<T> serializer;
|
private final JsonDeserializer<T> deserializer;
|
private final Gson gson;
|
private final TypeToken<T> typeToken;
|
private final TypeAdapterFactory skipPast;
|
|
/**
|
* The delegate is lazily created because it may not be needed, and creating it
|
* may fail.
|
*/
|
private TypeAdapter<T> delegate;
|
|
TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
|
this.serializer = serializer;
|
this.deserializer = deserializer;
|
this.gson = gson;
|
this.typeToken = typeToken;
|
this.skipPast = skipPast;
|
}
|
|
@Override
|
public T read(JsonReader in) throws IOException {
|
if (deserializer == null) {
|
return delegate().read(in);
|
}
|
JsonElement value = Streams.parse(in);
|
if (value.isJsonNull()) {
|
return null;
|
}
|
return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext);
|
}
|
|
@Override
|
public void write(JsonWriter out, T value) throws IOException {
|
if (serializer == null) {
|
delegate().write(out, value);
|
return;
|
}
|
if (value == null) {
|
out.nullValue();
|
return;
|
}
|
JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext);
|
Streams.write(tree, out);
|
}
|
|
private TypeAdapter<T> delegate() {
|
TypeAdapter<T> d = delegate;
|
return d != null ? d : (delegate = gson.getDelegateAdapter(skipPast, typeToken));
|
}
|
|
/**
|
* Returns a new factory that will match each type against {@code exactType}.
|
*/
|
public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {
|
return new SingleTypeFactory(typeAdapter, exactType, false, null);
|
}
|
|
/**
|
* Returns a new factory that will match each type and its raw type against
|
* {@code exactType}.
|
*/
|
public static TypeAdapterFactory newFactoryWithMatchRawType(TypeToken<?> exactType, Object typeAdapter) {
|
// only bother matching raw types if exact type is a raw type
|
boolean matchRawType = exactType.getType() == exactType.getRawType();
|
return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);
|
}
|
|
/**
|
* Returns a new factory that will match each type's raw type for assignability
|
* to {@code hierarchyType}.
|
*/
|
public static TypeAdapterFactory newTypeHierarchyFactory(Class<?> hierarchyType, Object typeAdapter) {
|
return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
|
}
|
|
private static class SingleTypeFactory implements TypeAdapterFactory {
|
private final TypeToken<?> exactType;
|
private final boolean matchRawType;
|
private final Class<?> hierarchyType;
|
private final JsonSerializer<?> serializer;
|
private final JsonDeserializer<?> deserializer;
|
|
SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, Class<?> hierarchyType) {
|
serializer = typeAdapter instanceof JsonSerializer ? (JsonSerializer<?>) typeAdapter : null;
|
deserializer = typeAdapter instanceof JsonDeserializer ? (JsonDeserializer<?>) typeAdapter : null;
|
$Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
|
this.exactType = exactType;
|
this.matchRawType = matchRawType;
|
this.hierarchyType = hierarchyType;
|
}
|
|
@SuppressWarnings("unchecked") // guarded by typeToken.equals() call
|
@Override
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
boolean matches = exactType != null ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() : hierarchyType.isAssignableFrom(type.getRawType());
|
return matches ? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer, (JsonDeserializer<T>) deserializer, gson, type, this) : null;
|
}
|
}
|
}
|