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