1 /*
2  * Copyright (C) 2014 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.JsonDeserializer;
21 import com.google.gson.JsonSerializer;
22 import com.google.gson.TypeAdapter;
23 import com.google.gson.TypeAdapterFactory;
24 import com.google.gson.annotations.JsonAdapter;
25 import com.google.gson.internal.ConstructorConstructor;
26 import com.google.gson.reflect.TypeToken;
27
28 /**
29  * Given a type T, looks for the annotation {@link JsonAdapter} and uses an instance of the
30  * specified class as the default type adapter.
31  *
32  * @since 2.3
33  */

34 public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory {
35   private final ConstructorConstructor constructorConstructor;
36
37   public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
38     this.constructorConstructor = constructorConstructor;
39   }
40
41   @SuppressWarnings("unchecked")
42   @Override
43   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
44     Class<? super T> rawType = targetType.getRawType();
45     JsonAdapter annotation = rawType.getAnnotation(JsonAdapter.class);
46     if (annotation == null) {
47       return null;
48     }
49     return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation);
50   }
51
52   @SuppressWarnings({ "unchecked""rawtypes" }) // Casts guarded by conditionals.
53   TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson,
54       TypeToken<?> type, JsonAdapter annotation) {
55     Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();
56
57     TypeAdapter<?> typeAdapter;
58     if (instance instanceof TypeAdapter) {
59       typeAdapter = (TypeAdapter<?>) instance;
60     } else if (instance instanceof TypeAdapterFactory) {
61       typeAdapter = ((TypeAdapterFactory) instance).create(gson, type);
62     } else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) {
63       JsonSerializer<?> serializer = instance instanceof JsonSerializer
64           ? (JsonSerializer) instance
65           : null;
66       JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
67           ? (JsonDeserializer) instance
68           : null;
69       typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
70     } else {
71       throw new IllegalArgumentException("Invalid attempt to bind an instance of "
72           + instance.getClass().getName() + " as a @JsonAdapter for " + type.toString()
73           + ". @JsonAdapter value must be a TypeAdapter, TypeAdapterFactory,"
74           + " JsonSerializer or JsonDeserializer.");
75     }
76
77     if (typeAdapter != null && annotation.nullSafe()) {
78       typeAdapter = typeAdapter.nullSafe();
79     }
80
81     return typeAdapter;
82   }
83 }
84