• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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;
18 
19 import com.google.gson.internal.$Gson$Types;
20 
21 import com.google.gson.internal.Primitives;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.ParameterizedType;
25 import java.lang.reflect.Type;
26 
27 
28 /**
29  * This class contains some test fixtures for Parameterized types. These classes should ideally
30  * belong either in the common or functional package, but they are placed here because they need
31  * access to package protected elements of com.google.gson.
32  *
33  * @author Inderjeet Singh
34  * @author Joel Leitch
35  */
36 public class ParameterizedTypeFixtures {
37 
38   public static class MyParameterizedType<T> {
39     public final T value;
MyParameterizedType(T value)40     public MyParameterizedType(T value) {
41       this.value = value;
42     }
getValue()43     public T getValue() {
44       return value;
45     }
46 
getExpectedJson()47     public String getExpectedJson() {
48       String valueAsJson = getExpectedJson(value);
49       return String.format("{\"value\":%s}", valueAsJson);
50     }
51 
getExpectedJson(Object obj)52     private String getExpectedJson(Object obj) {
53       Class<?> clazz = obj.getClass();
54       if (Primitives.isWrapperType(Primitives.wrap(clazz))) {
55         return obj.toString();
56       } else if (obj.getClass().equals(String.class)) {
57         return "\"" + obj.toString() + "\"";
58       } else {
59         // Try invoking a getExpectedJson() method if it exists
60         try {
61           Method method = clazz.getMethod("getExpectedJson");
62           Object results = method.invoke(obj);
63           return (String) results;
64         } catch (SecurityException e) {
65           throw new RuntimeException(e);
66         } catch (NoSuchMethodException e) {
67           throw new RuntimeException(e);
68         } catch (IllegalArgumentException e) {
69           throw new RuntimeException(e);
70         } catch (IllegalAccessException e) {
71           throw new RuntimeException(e);
72         } catch (InvocationTargetException e) {
73           throw new RuntimeException(e);
74         }
75       }
76     }
77 
78     @Override
hashCode()79     public int hashCode() {
80       return value == null ? 0 : value.hashCode();
81     }
82 
83     @SuppressWarnings("unchecked")
84     @Override
equals(Object obj)85     public boolean equals(Object obj) {
86       if (this == obj) {
87         return true;
88       }
89       if (obj == null) {
90         return false;
91       }
92       if (getClass() != obj.getClass()) {
93         return false;
94       }
95       MyParameterizedType<T> other = (MyParameterizedType<T>) obj;
96       if (value == null) {
97         if (other.value != null) {
98           return false;
99         }
100       } else if (!value.equals(other.value)) {
101         return false;
102       }
103       return true;
104     }
105   }
106 
107   public static class MyParameterizedTypeInstanceCreator<T>
108       implements InstanceCreator<MyParameterizedType<T>>{
109     private final T instanceOfT;
110     /**
111      * Caution the specified instance is reused by the instance creator for each call.
112      * This means that the fields of the same objects will be overwritten by Gson.
113      * This is usually fine in tests since there we deserialize just once, but quite
114      * dangerous in practice.
115      *
116      * @param instanceOfT
117      */
MyParameterizedTypeInstanceCreator(T instanceOfT)118     public MyParameterizedTypeInstanceCreator(T instanceOfT) {
119       this.instanceOfT = instanceOfT;
120     }
createInstance(Type type)121     @Override public MyParameterizedType<T> createInstance(Type type) {
122       return new MyParameterizedType<>(instanceOfT);
123     }
124   }
125 
126   public static final class MyParameterizedTypeAdapter<T>
127   implements JsonSerializer<MyParameterizedType<T>>, JsonDeserializer<MyParameterizedType<T>> {
128     @SuppressWarnings("unchecked")
getExpectedJson(MyParameterizedType<T> obj)129     public static<T> String getExpectedJson(MyParameterizedType<T> obj) {
130       Class<T> clazz = (Class<T>) obj.value.getClass();
131       boolean addQuotes = !clazz.isArray() && !Primitives.unwrap(clazz).isPrimitive();
132       StringBuilder sb = new StringBuilder("{\"");
133       sb.append(obj.value.getClass().getSimpleName()).append("\":");
134       if (addQuotes) {
135         sb.append("\"");
136       }
137       sb.append(obj.value.toString());
138       if (addQuotes) {
139         sb.append("\"");
140       }
141       sb.append("}");
142       return sb.toString();
143     }
144 
serialize(MyParameterizedType<T> src, Type classOfSrc, JsonSerializationContext context)145     @Override public JsonElement serialize(MyParameterizedType<T> src, Type classOfSrc,
146         JsonSerializationContext context) {
147       JsonObject json = new JsonObject();
148       T value = src.getValue();
149       json.add(value.getClass().getSimpleName(), context.serialize(value));
150       return json;
151     }
152 
153     @SuppressWarnings("unchecked")
deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)154     @Override public MyParameterizedType<T> deserialize(JsonElement json, Type typeOfT,
155         JsonDeserializationContext context) throws JsonParseException {
156       Type genericClass = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
157       Class<?> rawType = $Gson$Types.getRawType(genericClass);
158       String className = rawType.getSimpleName();
159       JsonElement jsonElement = json.getAsJsonObject().get(className);
160 
161       T value;
162       if (genericClass == Integer.class) {
163         value = (T) Integer.valueOf(jsonElement.getAsInt());
164       } else if (genericClass == String.class) {
165         value = (T) jsonElement.getAsString();
166       } else {
167         value = (T) jsonElement;
168       }
169 
170       if (Primitives.isPrimitive(genericClass)) {
171         PrimitiveTypeAdapter typeAdapter = new PrimitiveTypeAdapter();
172         value = (T) typeAdapter.adaptType(value, rawType);
173       }
174       return new MyParameterizedType<>(value);
175     }
176   }
177 }
178