• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.caliper.json;
18 
19 import com.google.common.collect.ImmutableListMultimap;
20 import com.google.common.collect.ImmutableMultimap;
21 import com.google.common.collect.ImmutableSetMultimap;
22 import com.google.common.collect.ListMultimap;
23 import com.google.common.collect.SetMultimap;
24 import com.google.common.reflect.TypeParameter;
25 import com.google.common.reflect.TypeToken;
26 import com.google.gson.Gson;
27 import com.google.gson.TypeAdapter;
28 import com.google.gson.TypeAdapterFactory;
29 import com.google.gson.stream.JsonReader;
30 import com.google.gson.stream.JsonWriter;
31 
32 import java.io.IOException;
33 import java.lang.reflect.ParameterizedType;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.Set;
38 
39 /**
40  * Serializes and deserializes {@link ImmutableMultimap} instances using maps of collections as
41  * intermediaries.
42  */
43 final class ImmutableMultimapTypeAdapterFactory implements TypeAdapterFactory {
getMapOfListsToken( TypeToken<ListMultimap<K, V>> from)44   private static <K, V> TypeToken<Map<K, List<V>>> getMapOfListsToken(
45       TypeToken<ListMultimap<K, V>> from) {
46     ParameterizedType rawType = (ParameterizedType) from.getSupertype(ListMultimap.class).getType();
47     @SuppressWarnings("unchecked") // key type is K
48     TypeToken<K> keyType = (TypeToken<K>) TypeToken.of(rawType.getActualTypeArguments()[0]);
49     @SuppressWarnings("unchecked") // value type is V
50     TypeToken<V> valueType = (TypeToken<V>) TypeToken.of(rawType.getActualTypeArguments()[1]);
51     return new TypeToken<Map<K, List<V>>>() {}
52         .where(new TypeParameter<K>() {}, keyType)
53         .where(new TypeParameter<V>() {}, valueType);
54   }
55 
getMapOfSetsToken( TypeToken<SetMultimap<K, V>> from)56   private static <K, V> TypeToken<Map<K, Set<V>>> getMapOfSetsToken(
57       TypeToken<SetMultimap<K, V>> from) {
58     ParameterizedType rawType = (ParameterizedType) from.getSupertype(SetMultimap.class).getType();
59     @SuppressWarnings("unchecked") // key type is K
60     TypeToken<K> keyType = (TypeToken<K>) TypeToken.of(rawType.getActualTypeArguments()[0]);
61     @SuppressWarnings("unchecked") // value type is V
62     TypeToken<V> valueType = (TypeToken<V>) TypeToken.of(rawType.getActualTypeArguments()[1]);
63     return new TypeToken<Map<K, Set<V>>>() {}
64         .where(new TypeParameter<K>() {}, keyType)
65         .where(new TypeParameter<V>() {}, valueType);
66   }
67 
68   @Override
69   @SuppressWarnings({"unchecked", "rawtypes"})
create(Gson gson, com.google.gson.reflect.TypeToken<T> typeToken)70   public <T> TypeAdapter<T> create(Gson gson, com.google.gson.reflect.TypeToken<T> typeToken) {
71     if (ImmutableListMultimap.class.isAssignableFrom(typeToken.getRawType())) {
72       TypeToken<Map<?, List<?>>> mapToken =
73           getMapOfListsToken((TypeToken) TypeToken.of(typeToken.getType()));
74       final TypeAdapter<Map<?, List<?>>> adapter =
75           (TypeAdapter<Map<?, List<?>>>) gson.getAdapter(
76               com.google.gson.reflect.TypeToken.get(mapToken.getType()));
77       return new TypeAdapter<T>() {
78         @Override public void write(JsonWriter out, T value) throws IOException {
79           ImmutableListMultimap<?, ?> multimap = (ImmutableListMultimap<?, ?>) value;
80           adapter.write(out, (Map) multimap.asMap());
81         }
82 
83         @Override public T read(JsonReader in) throws IOException {
84           Map<?, List<?>> value = adapter.read(in);
85           ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
86           for (Entry<?, List<?>> entry : value.entrySet()) {
87             builder.putAll(entry.getKey(), entry.getValue());
88           }
89           return (T) builder.build();
90         }
91       };
92     } else if (ImmutableSetMultimap.class.isAssignableFrom(typeToken.getRawType())) {
93       TypeToken<Map<?, Set<?>>> mapToken =
94           getMapOfSetsToken((TypeToken) TypeToken.of(typeToken.getType()));
95       final TypeAdapter<Map<?, Set<?>>> adapter =
96           (TypeAdapter<Map<?, Set<?>>>) gson.getAdapter(
97               com.google.gson.reflect.TypeToken.get(mapToken.getType()));
98       return new TypeAdapter<T>() {
99         @Override public void write(JsonWriter out, T value) throws IOException {
100           ImmutableSetMultimap<?, ?> multimap = (ImmutableSetMultimap<?, ?>) value;
101           adapter.write(out, (Map) multimap.asMap());
102         }
103 
104         @Override public T read(JsonReader in) throws IOException {
105           Map<?, Set<?>> value = adapter.read(in);
106           ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder();
107           for (Entry<?, Set<?>> entry : value.entrySet()) {
108             builder.putAll(entry.getKey(), entry.getValue());
109           }
110           return (T) builder.build();
111         }
112       };
113     } else {
114       return null;
115     }
116   }
117 }
118