/*
 * Copyright (C) 2014 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 com.google.gson.internal.bind;

import com.google.gson.Gson;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.reflect.TypeToken;

Given a type T, looks for the annotation JsonAdapter and uses an instance of the specified class as the default type adapter.
Since:2.3
/** * Given a type T, looks for the annotation {@link JsonAdapter} and uses an instance of the * specified class as the default type adapter. * * @since 2.3 */
public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory { private final ConstructorConstructor constructorConstructor; public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) { this.constructorConstructor = constructorConstructor; } @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) { Class<? super T> rawType = targetType.getRawType(); JsonAdapter annotation = rawType.getAnnotation(JsonAdapter.class); if (annotation == null) { return null; } return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation); } @SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals. TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson, TypeToken<?> type, JsonAdapter annotation) { Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct(); TypeAdapter<?> typeAdapter; if (instance instanceof TypeAdapter) { typeAdapter = (TypeAdapter<?>) instance; } else if (instance instanceof TypeAdapterFactory) { typeAdapter = ((TypeAdapterFactory) instance).create(gson, type); } else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) { JsonSerializer<?> serializer = instance instanceof JsonSerializer ? (JsonSerializer) instance : null; JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer ? (JsonDeserializer) instance : null; typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null); } else { throw new IllegalArgumentException("Invalid attempt to bind an instance of " + instance.getClass().getName() + " as a @JsonAdapter for " + type.toString() + ". @JsonAdapter value must be a TypeAdapter, TypeAdapterFactory," + " JsonSerializer or JsonDeserializer."); } if (typeAdapter != null && annotation.nullSafe()) { typeAdapter = typeAdapter.nullSafe(); } return typeAdapter; } }