2 * Copyright (C) 2011 Google Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.google
.gson
.internal
.bind
;
18 import com
.google
.gson
.Gson
;
19 import com
.google
.gson
.TypeAdapter
;
20 import com
.google
.gson
.reflect
.TypeToken
;
21 import com
.google
.gson
.stream
.JsonReader
;
22 import com
.google
.gson
.stream
.JsonWriter
;
23 import java
.io
.IOException
;
24 import java
.lang
.reflect
.Type
;
25 import java
.lang
.reflect
.TypeVariable
;
27 final class TypeAdapterRuntimeTypeWrapper
<T
> extends TypeAdapter
<T
> {
28 private final Gson context
;
29 private final TypeAdapter
<T
> delegate
;
30 private final Type type
;
32 TypeAdapterRuntimeTypeWrapper(Gson context
, TypeAdapter
<T
> delegate
, Type type
) {
33 this.context
= context
;
34 this.delegate
= delegate
;
39 public T
read(JsonReader in
) throws IOException
{
40 return delegate
.read(in
);
43 @SuppressWarnings({"rawtypes", "unchecked"})
45 public void write(JsonWriter out
, T value
) throws IOException
{
46 // Order of preference for choosing type adapters
47 // First preference: a type adapter registered for the runtime type
48 // Second preference: a type adapter registered for the declared type
49 // Third preference: reflective type adapter for the runtime type (if it is a sub class of the declared type)
50 // Fourth preference: reflective type adapter for the declared type
52 TypeAdapter chosen
= delegate
;
53 Type runtimeType
= getRuntimeTypeIfMoreSpecific(type
, value
);
54 if (runtimeType
!= type
) {
55 TypeAdapter runtimeTypeAdapter
= context
.getAdapter(TypeToken
.get(runtimeType
));
56 if (!(runtimeTypeAdapter
instanceof ReflectiveTypeAdapterFactory
.Adapter
)) {
57 // The user registered a type adapter for the runtime type, so we will use that
58 chosen
= runtimeTypeAdapter
;
59 } else if (!(delegate
instanceof ReflectiveTypeAdapterFactory
.Adapter
)) {
60 // The user registered a type adapter for Base class, so we prefer it over the
61 // reflective type adapter for the runtime type
64 // Use the type adapter for runtime type
65 chosen
= runtimeTypeAdapter
;
68 chosen
.write(out
, value
);
72 * Finds a compatible runtime type if it is more specific
74 private Type
getRuntimeTypeIfMoreSpecific(Type type
, Object value
) {
76 && (type
== Object
.class || type
instanceof TypeVariable
<?
> || type
instanceof Class
<?
>)) {
77 type
= value
.getClass();