2011-11-20 20:55:01 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2016-03-28 23:46:02 +02:00
|
|
|
package com.google.gson.internal.bind;
|
2011-11-20 20:55:01 +01:00
|
|
|
|
2016-03-28 23:46:02 +02:00
|
|
|
import com.google.gson.Gson;
|
|
|
|
import com.google.gson.JsonDeserializationContext;
|
|
|
|
import com.google.gson.JsonDeserializer;
|
|
|
|
import com.google.gson.JsonElement;
|
|
|
|
import com.google.gson.JsonParseException;
|
|
|
|
import com.google.gson.JsonSerializationContext;
|
|
|
|
import com.google.gson.JsonSerializer;
|
|
|
|
import com.google.gson.TypeAdapter;
|
|
|
|
import com.google.gson.TypeAdapterFactory;
|
2011-11-20 20:55:01 +01:00
|
|
|
import com.google.gson.internal.$Gson$Preconditions;
|
|
|
|
import com.google.gson.internal.Streams;
|
|
|
|
import com.google.gson.reflect.TypeToken;
|
|
|
|
import com.google.gson.stream.JsonReader;
|
|
|
|
import com.google.gson.stream.JsonWriter;
|
|
|
|
import java.io.IOException;
|
2016-03-28 23:46:02 +02:00
|
|
|
import java.lang.reflect.Type;
|
2011-11-20 20:55:01 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-10-11 01:10:48 +02:00
|
|
|
public final class TreeTypeAdapter<T> extends SerializationDelegatingTypeAdapter<T> {
|
2011-11-20 20:55:01 +01:00
|
|
|
private final JsonSerializer<T> serializer;
|
|
|
|
private final JsonDeserializer<T> deserializer;
|
2017-04-23 02:32:59 +02:00
|
|
|
final Gson gson;
|
2011-11-20 20:55:01 +01:00
|
|
|
private final TypeToken<T> typeToken;
|
2011-12-23 19:27:13 +01:00
|
|
|
private final TypeAdapterFactory skipPast;
|
2016-03-28 23:46:02 +02:00
|
|
|
private final GsonContextImpl context = new GsonContextImpl();
|
2022-08-05 16:33:05 +02:00
|
|
|
private final boolean nullSafe;
|
2011-11-20 20:55:01 +01:00
|
|
|
|
|
|
|
/** The delegate is lazily created because it may not be needed, and creating it may fail. */
|
2021-11-01 23:13:08 +01:00
|
|
|
private volatile TypeAdapter<T> delegate;
|
2011-11-20 20:55:01 +01:00
|
|
|
|
2016-03-28 23:46:02 +02:00
|
|
|
public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
|
2022-08-05 16:33:05 +02:00
|
|
|
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast, boolean nullSafe) {
|
2011-11-20 20:55:01 +01:00
|
|
|
this.serializer = serializer;
|
|
|
|
this.deserializer = deserializer;
|
|
|
|
this.gson = gson;
|
|
|
|
this.typeToken = typeToken;
|
|
|
|
this.skipPast = skipPast;
|
2022-08-05 16:33:05 +02:00
|
|
|
this.nullSafe = nullSafe;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
|
|
|
|
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
|
|
|
|
this(serializer, deserializer, gson, typeToken, skipPast, true);
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
|
|
|
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public T read(JsonReader in) throws IOException {
|
2011-11-20 20:55:01 +01:00
|
|
|
if (deserializer == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
return delegate().read(in);
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
JsonElement value = Streams.parse(in);
|
2022-08-05 16:33:05 +02:00
|
|
|
if (nullSafe && value.isJsonNull()) {
|
2011-11-20 20:55:01 +01:00
|
|
|
return null;
|
|
|
|
}
|
2016-03-28 23:46:02 +02:00
|
|
|
return deserializer.deserialize(value, typeToken.getType(), context);
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
|
|
|
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public void write(JsonWriter out, T value) throws IOException {
|
2011-11-20 20:55:01 +01:00
|
|
|
if (serializer == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
delegate().write(out, value);
|
2011-11-20 20:55:01 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-08-05 16:33:05 +02:00
|
|
|
if (nullSafe && value == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
out.nullValue();
|
2011-11-20 20:55:01 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-03-28 23:46:02 +02:00
|
|
|
JsonElement tree = serializer.serialize(value, typeToken.getType(), context);
|
2011-12-03 20:46:25 +01:00
|
|
|
Streams.write(tree, out);
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private TypeAdapter<T> delegate() {
|
2021-11-01 23:13:08 +01:00
|
|
|
// A race might lead to `delegate` being assigned by multiple threads but the last assignment will stick
|
2011-11-20 20:55:01 +01:00
|
|
|
TypeAdapter<T> d = delegate;
|
|
|
|
return d != null
|
|
|
|
? d
|
2012-04-12 20:49:27 +02:00
|
|
|
: (delegate = gson.getDelegateAdapter(skipPast, typeToken));
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
|
|
|
|
2022-10-11 01:10:48 +02:00
|
|
|
/**
|
|
|
|
* Returns the type adapter which is used for serialization. Returns {@code this}
|
|
|
|
* if this {@code TreeTypeAdapter} has a {@link #serializer}; otherwise returns
|
|
|
|
* the delegate.
|
|
|
|
*/
|
|
|
|
@Override public TypeAdapter<T> getSerializationDelegate() {
|
|
|
|
return serializer != null ? this : delegate();
|
|
|
|
}
|
|
|
|
|
2011-11-23 14:38:25 +01:00
|
|
|
/**
|
|
|
|
* Returns a new factory that will match each type against {@code exactType}.
|
|
|
|
*/
|
2011-12-23 19:27:13 +01:00
|
|
|
public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {
|
2011-11-23 14:38:25 +01:00
|
|
|
return new SingleTypeFactory(typeAdapter, exactType, false, null);
|
2011-11-23 07:16:55 +01:00
|
|
|
}
|
|
|
|
|
2011-11-23 14:38:25 +01:00
|
|
|
/**
|
|
|
|
* Returns a new factory that will match each type and its raw type against
|
|
|
|
* {@code exactType}.
|
|
|
|
*/
|
2011-12-23 19:27:13 +01:00
|
|
|
public static TypeAdapterFactory newFactoryWithMatchRawType(
|
|
|
|
TypeToken<?> exactType, Object typeAdapter) {
|
2011-11-23 14:38:25 +01:00
|
|
|
// 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}.
|
|
|
|
*/
|
2011-12-23 19:27:13 +01:00
|
|
|
public static TypeAdapterFactory newTypeHierarchyFactory(
|
|
|
|
Class<?> hierarchyType, Object typeAdapter) {
|
2011-11-23 14:38:25 +01:00
|
|
|
return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
|
2011-11-23 07:16:55 +01:00
|
|
|
}
|
|
|
|
|
2016-03-28 23:46:02 +02:00
|
|
|
private static final class SingleTypeFactory implements TypeAdapterFactory {
|
2011-11-23 07:16:55 +01:00
|
|
|
private final TypeToken<?> exactType;
|
2011-11-23 14:38:25 +01:00
|
|
|
private final boolean matchRawType;
|
2011-11-23 07:16:55 +01:00
|
|
|
private final Class<?> hierarchyType;
|
2011-11-20 20:55:01 +01:00
|
|
|
private final JsonSerializer<?> serializer;
|
|
|
|
private final JsonDeserializer<?> deserializer;
|
|
|
|
|
2015-12-27 07:39:19 +01:00
|
|
|
SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,
|
2011-11-23 14:38:25 +01:00
|
|
|
Class<?> hierarchyType) {
|
2011-11-20 20:55:01 +01:00
|
|
|
serializer = typeAdapter instanceof JsonSerializer
|
2011-12-04 11:24:07 +01:00
|
|
|
? (JsonSerializer<?>) typeAdapter
|
2011-11-20 20:55:01 +01:00
|
|
|
: null;
|
|
|
|
deserializer = typeAdapter instanceof JsonDeserializer
|
2011-12-04 11:24:07 +01:00
|
|
|
? (JsonDeserializer<?>) typeAdapter
|
2011-11-20 20:55:01 +01:00
|
|
|
: null;
|
|
|
|
$Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
|
2011-11-23 07:16:55 +01:00
|
|
|
this.exactType = exactType;
|
2011-11-23 14:38:25 +01:00
|
|
|
this.matchRawType = matchRawType;
|
2011-11-23 07:16:55 +01:00
|
|
|
this.hierarchyType = hierarchyType;
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") // guarded by typeToken.equals() call
|
2015-11-05 03:52:20 +01:00
|
|
|
@Override
|
2011-12-02 23:57:30 +01:00
|
|
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
2011-11-23 07:16:55 +01:00
|
|
|
boolean matches = exactType != null
|
2023-02-15 14:18:43 +01:00
|
|
|
? exactType.equals(type) || (matchRawType && exactType.getType() == type.getRawType())
|
2011-11-23 07:16:55 +01:00
|
|
|
: hierarchyType.isAssignableFrom(type.getRawType());
|
|
|
|
return matches
|
2022-04-18 00:27:21 +02:00
|
|
|
? new TreeTypeAdapter<>((JsonSerializer<T>) serializer,
|
2011-12-02 23:57:30 +01:00
|
|
|
(JsonDeserializer<T>) deserializer, gson, type, this)
|
2011-11-20 20:55:01 +01:00
|
|
|
: null;
|
|
|
|
}
|
|
|
|
}
|
2016-03-28 23:46:02 +02:00
|
|
|
|
|
|
|
private final class GsonContextImpl implements JsonSerializationContext, JsonDeserializationContext {
|
|
|
|
@Override public JsonElement serialize(Object src) {
|
|
|
|
return gson.toJsonTree(src);
|
|
|
|
}
|
|
|
|
@Override public JsonElement serialize(Object src, Type typeOfSrc) {
|
|
|
|
return gson.toJsonTree(src, typeOfSrc);
|
|
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@Override public <R> R deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
2022-12-13 17:50:25 +01:00
|
|
|
return gson.fromJson(json, typeOfT);
|
2016-03-28 23:46:02 +02:00
|
|
|
}
|
2022-10-11 01:10:48 +02:00
|
|
|
}
|
2011-11-20 20:55:01 +01:00
|
|
|
}
|