blob: 978138819ec93f951ab5287564c2d9984cf3a2e1 [file] [log] [blame]
/*
* Copyright (C) 2012 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.caliper.json;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.SetMultimap;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Serializes and deserializes {@link ImmutableMultimap} instances using maps of collections as
* intermediaries.
*/
final class ImmutableMultimapTypeAdapterFactory implements TypeAdapterFactory {
private static <K, V> TypeToken<Map<K, List<V>>> getMapOfListsToken(
TypeToken<ListMultimap<K, V>> from) {
ParameterizedType rawType = (ParameterizedType) from.getSupertype(ListMultimap.class).getType();
@SuppressWarnings("unchecked") // key type is K
TypeToken<K> keyType = (TypeToken<K>) TypeToken.of(rawType.getActualTypeArguments()[0]);
@SuppressWarnings("unchecked") // value type is V
TypeToken<V> valueType = (TypeToken<V>) TypeToken.of(rawType.getActualTypeArguments()[1]);
return new TypeToken<Map<K, List<V>>>() {}
.where(new TypeParameter<K>() {}, keyType)
.where(new TypeParameter<V>() {}, valueType);
}
private static <K, V> TypeToken<Map<K, Set<V>>> getMapOfSetsToken(
TypeToken<SetMultimap<K, V>> from) {
ParameterizedType rawType = (ParameterizedType) from.getSupertype(SetMultimap.class).getType();
@SuppressWarnings("unchecked") // key type is K
TypeToken<K> keyType = (TypeToken<K>) TypeToken.of(rawType.getActualTypeArguments()[0]);
@SuppressWarnings("unchecked") // value type is V
TypeToken<V> valueType = (TypeToken<V>) TypeToken.of(rawType.getActualTypeArguments()[1]);
return new TypeToken<Map<K, Set<V>>>() {}
.where(new TypeParameter<K>() {}, keyType)
.where(new TypeParameter<V>() {}, valueType);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> TypeAdapter<T> create(Gson gson, com.google.gson.reflect.TypeToken<T> typeToken) {
if (ImmutableListMultimap.class.isAssignableFrom(typeToken.getRawType())) {
TypeToken<Map<?, List<?>>> mapToken =
getMapOfListsToken((TypeToken) TypeToken.of(typeToken.getType()));
final TypeAdapter<Map<?, List<?>>> adapter =
(TypeAdapter<Map<?, List<?>>>) gson.getAdapter(
com.google.gson.reflect.TypeToken.get(mapToken.getType()));
return new TypeAdapter<T>() {
@Override public void write(JsonWriter out, T value) throws IOException {
ImmutableListMultimap<?, ?> multimap = (ImmutableListMultimap<?, ?>) value;
adapter.write(out, (Map) multimap.asMap());
}
@Override public T read(JsonReader in) throws IOException {
Map<?, List<?>> value = adapter.read(in);
ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
for (Entry<?, List<?>> entry : value.entrySet()) {
builder.putAll(entry.getKey(), entry.getValue());
}
return (T) builder.build();
}
};
} else if (ImmutableSetMultimap.class.isAssignableFrom(typeToken.getRawType())) {
TypeToken<Map<?, Set<?>>> mapToken =
getMapOfSetsToken((TypeToken) TypeToken.of(typeToken.getType()));
final TypeAdapter<Map<?, Set<?>>> adapter =
(TypeAdapter<Map<?, Set<?>>>) gson.getAdapter(
com.google.gson.reflect.TypeToken.get(mapToken.getType()));
return new TypeAdapter<T>() {
@Override public void write(JsonWriter out, T value) throws IOException {
ImmutableSetMultimap<?, ?> multimap = (ImmutableSetMultimap<?, ?>) value;
adapter.write(out, (Map) multimap.asMap());
}
@Override public T read(JsonReader in) throws IOException {
Map<?, Set<?>> value = adapter.read(in);
ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder();
for (Entry<?, Set<?>> entry : value.entrySet()) {
builder.putAll(entry.getKey(), entry.getValue());
}
return (T) builder.build();
}
};
} else {
return null;
}
}
}