1 /* 2 * Copyright (C) 2011 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.functional; 18 19 import com.google.gson.Gson; 20 import com.google.gson.GsonBuilder; 21 import com.google.gson.JsonDeserializationContext; 22 import com.google.gson.JsonDeserializer; 23 import com.google.gson.JsonElement; 24 import com.google.gson.JsonObject; 25 import com.google.gson.JsonParseException; 26 import com.google.gson.JsonPrimitive; 27 import com.google.gson.JsonSerializationContext; 28 import com.google.gson.JsonSerializer; 29 import java.lang.reflect.Type; 30 import junit.framework.TestCase; 31 32 /** 33 * Test that the hierarchy adapter works when subtypes are used. 34 */ 35 public final class TypeHierarchyAdapterTest extends TestCase { 36 testTypeHierarchy()37 public void testTypeHierarchy() { 38 Manager andy = new Manager(); 39 andy.userid = "andy"; 40 andy.startDate = 2005; 41 andy.minions = new Employee[] { 42 new Employee("inder", 2007), 43 new Employee("joel", 2006), 44 new Employee("jesse", 2006), 45 }; 46 47 CEO eric = new CEO(); 48 eric.userid = "eric"; 49 eric.startDate = 2001; 50 eric.assistant = new Employee("jerome", 2006); 51 52 eric.minions = new Employee[] { 53 new Employee("larry", 1998), 54 new Employee("sergey", 1998), 55 andy, 56 }; 57 58 Gson gson = new GsonBuilder() 59 .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) 60 .setPrettyPrinting() 61 .create(); 62 63 Company company = new Company(); 64 company.ceo = eric; 65 66 String json = gson.toJson(company, Company.class); 67 assertEquals("{\n" + 68 " \"ceo\": {\n" + 69 " \"userid\": \"eric\",\n" + 70 " \"startDate\": 2001,\n" + 71 " \"minions\": [\n" + 72 " {\n" + 73 " \"userid\": \"larry\",\n" + 74 " \"startDate\": 1998\n" + 75 " },\n" + 76 " {\n" + 77 " \"userid\": \"sergey\",\n" + 78 " \"startDate\": 1998\n" + 79 " },\n" + 80 " {\n" + 81 " \"userid\": \"andy\",\n" + 82 " \"startDate\": 2005,\n" + 83 " \"minions\": [\n" + 84 " {\n" + 85 " \"userid\": \"inder\",\n" + 86 " \"startDate\": 2007\n" + 87 " },\n" + 88 " {\n" + 89 " \"userid\": \"joel\",\n" + 90 " \"startDate\": 2006\n" + 91 " },\n" + 92 " {\n" + 93 " \"userid\": \"jesse\",\n" + 94 " \"startDate\": 2006\n" + 95 " }\n" + 96 " ]\n" + 97 " }\n" + 98 " ],\n" + 99 " \"assistant\": {\n" + 100 " \"userid\": \"jerome\",\n" + 101 " \"startDate\": 2006\n" + 102 " }\n" + 103 " }\n" + 104 "}", json); 105 106 Company copied = gson.fromJson(json, Company.class); 107 assertEquals(json, gson.toJson(copied, Company.class)); 108 assertEquals(copied.ceo.userid, company.ceo.userid); 109 assertEquals(copied.ceo.assistant.userid, company.ceo.assistant.userid); 110 assertEquals(copied.ceo.minions[0].userid, company.ceo.minions[0].userid); 111 assertEquals(copied.ceo.minions[1].userid, company.ceo.minions[1].userid); 112 assertEquals(copied.ceo.minions[2].userid, company.ceo.minions[2].userid); 113 assertEquals(((Manager) copied.ceo.minions[2]).minions[0].userid, 114 ((Manager) company.ceo.minions[2]).minions[0].userid); 115 assertEquals(((Manager) copied.ceo.minions[2]).minions[1].userid, 116 ((Manager) company.ceo.minions[2]).minions[1].userid); 117 } 118 testRegisterSuperTypeFirst()119 public void testRegisterSuperTypeFirst() { 120 Gson gson = new GsonBuilder() 121 .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) 122 .registerTypeHierarchyAdapter(Manager.class, new ManagerAdapter()) 123 .create(); 124 125 Manager manager = new Manager(); 126 manager.userid = "inder"; 127 128 String json = gson.toJson(manager, Manager.class); 129 assertEquals("\"inder\"", json); 130 Manager copied = gson.fromJson(json, Manager.class); 131 assertEquals(manager.userid, copied.userid); 132 } 133 134 /** This behaviour changed in Gson 2.1; it used to throw. */ testRegisterSubTypeFirstAllowed()135 public void testRegisterSubTypeFirstAllowed() { 136 new GsonBuilder() 137 .registerTypeHierarchyAdapter(Manager.class, new ManagerAdapter()) 138 .registerTypeHierarchyAdapter(Employee.class, new EmployeeAdapter()) 139 .create(); 140 } 141 142 static class ManagerAdapter implements JsonSerializer<Manager>, JsonDeserializer<Manager> { deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)143 @Override public Manager deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { 144 Manager result = new Manager(); 145 result.userid = json.getAsString(); 146 return result; 147 } serialize(Manager src, Type typeOfSrc, JsonSerializationContext context)148 @Override public JsonElement serialize(Manager src, Type typeOfSrc, JsonSerializationContext context) { 149 return new JsonPrimitive(src.userid); 150 } 151 } 152 153 static class EmployeeAdapter implements JsonSerializer<Employee>, JsonDeserializer<Employee> { serialize(Employee employee, Type typeOfSrc, JsonSerializationContext context)154 @Override public JsonElement serialize(Employee employee, Type typeOfSrc, 155 JsonSerializationContext context) { 156 JsonObject result = new JsonObject(); 157 result.add("userid", context.serialize(employee.userid, String.class)); 158 result.add("startDate", context.serialize(employee.startDate, long.class)); 159 if (employee instanceof Manager) { 160 result.add("minions", context.serialize(((Manager) employee).minions, Employee[].class)); 161 if (employee instanceof CEO) { 162 result.add("assistant", context.serialize(((CEO) employee).assistant, Employee.class)); 163 } 164 } 165 return result; 166 } 167 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)168 @Override public Employee deserialize(JsonElement json, Type typeOfT, 169 JsonDeserializationContext context) throws JsonParseException { 170 JsonObject object = json.getAsJsonObject(); 171 Employee result = null; 172 173 // if the employee has an assistant, she must be the CEO 174 JsonElement assistant = object.get("assistant"); 175 if (assistant != null) { 176 result = new CEO(); 177 ((CEO) result).assistant = context.deserialize(assistant, Employee.class); 178 } 179 180 // only managers have minions 181 JsonElement minons = object.get("minions"); 182 if (minons != null) { 183 if (result == null) { 184 result = new Manager(); 185 } 186 ((Manager) result).minions = context.deserialize(minons, Employee[].class); 187 } 188 189 if (result == null) { 190 result = new Employee(); 191 } 192 result.userid = context.deserialize(object.get("userid"), String.class); 193 result.startDate = context.<Long>deserialize(object.get("startDate"), long.class); 194 return result; 195 } 196 } 197 198 static class Employee { 199 String userid; 200 long startDate; 201 Employee(String userid, long startDate)202 Employee(String userid, long startDate) { 203 this.userid = userid; 204 this.startDate = startDate; 205 } 206 Employee()207 Employee() {} 208 } 209 210 static class Manager extends Employee { 211 Employee[] minions; 212 } 213 214 static class CEO extends Manager { 215 Employee assistant; 216 } 217 218 static class Company { 219 CEO ceo; 220 } 221 } 222