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.JsonParseException; 25 import com.google.gson.JsonPrimitive; 26 import com.google.gson.JsonSerializationContext; 27 import com.google.gson.JsonSerializer; 28 import com.google.gson.reflect.TypeToken; 29 import java.lang.reflect.ParameterizedType; 30 import java.lang.reflect.Type; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.List; 34 import junit.framework.TestCase; 35 36 /** 37 * Collection of functional tests for DOM tree based type adapters. 38 */ 39 public class TreeTypeAdaptersTest extends TestCase { 40 private static final Id<Student> STUDENT1_ID = new Id<>("5", Student.class); 41 private static final Id<Student> STUDENT2_ID = new Id<>("6", Student.class); 42 private static final Student STUDENT1 = new Student(STUDENT1_ID, "first"); 43 private static final Student STUDENT2 = new Student(STUDENT2_ID, "second"); 44 private static final Type TYPE_COURSE_HISTORY = 45 new TypeToken<Course<HistoryCourse>>(){}.getType(); 46 private static final Id<Course<HistoryCourse>> COURSE_ID = 47 new Id<>("10", TYPE_COURSE_HISTORY); 48 49 private Gson gson; 50 private Course<HistoryCourse> course; 51 52 @Override setUp()53 protected void setUp() { 54 gson = new GsonBuilder() 55 .registerTypeAdapter(Id.class, new IdTreeTypeAdapter()) 56 .create(); 57 course = new Course<>(COURSE_ID, 4, 58 new Assignment<HistoryCourse>(null, null), Arrays.asList(STUDENT1, STUDENT2)); 59 } 60 testSerializeId()61 public void testSerializeId() { 62 String json = gson.toJson(course, TYPE_COURSE_HISTORY); 63 assertTrue(json.contains(String.valueOf(COURSE_ID.getValue()))); 64 assertTrue(json.contains(String.valueOf(STUDENT1_ID.getValue()))); 65 assertTrue(json.contains(String.valueOf(STUDENT2_ID.getValue()))); 66 } 67 testDeserializeId()68 public void testDeserializeId() { 69 String json = "{courseId:1,students:[{id:1,name:'first'},{id:6,name:'second'}]," 70 + "numAssignments:4,assignment:{}}"; 71 Course<HistoryCourse> target = gson.fromJson(json, TYPE_COURSE_HISTORY); 72 assertEquals("1", target.getStudents().get(0).id.getValue()); 73 assertEquals("6", target.getStudents().get(1).id.getValue()); 74 assertEquals("1", target.getId().getValue()); 75 } 76 77 private static final class Id<R> { 78 final String value; 79 @SuppressWarnings("unused") 80 final Type typeOfId; 81 Id(String value, Type typeOfId)82 private Id(String value, Type typeOfId) { 83 this.value = value; 84 this.typeOfId = typeOfId; 85 } getValue()86 public String getValue() { 87 return value; 88 } 89 } 90 91 private static final class IdTreeTypeAdapter implements JsonSerializer<Id<?>>, 92 JsonDeserializer<Id<?>> { 93 94 @Override deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)95 public Id<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 96 throws JsonParseException { 97 if (!(typeOfT instanceof ParameterizedType)) { 98 throw new JsonParseException("Id of unknown type: " + typeOfT); 99 } 100 ParameterizedType parameterizedType = (ParameterizedType) typeOfT; 101 // Since Id takes only one TypeVariable, the actual type corresponding to the first 102 // TypeVariable is the Type we are looking for 103 Type typeOfId = parameterizedType.getActualTypeArguments()[0]; 104 return new Id<>(json.getAsString(), typeOfId); 105 } 106 107 @Override serialize(Id<?> src, Type typeOfSrc, JsonSerializationContext context)108 public JsonElement serialize(Id<?> src, Type typeOfSrc, JsonSerializationContext context) { 109 return new JsonPrimitive(src.getValue()); 110 } 111 } 112 113 @SuppressWarnings("unused") 114 private static class Student { 115 Id<Student> id; 116 String name; 117 Student()118 private Student() { 119 this(null, null); 120 } Student(Id<Student> id, String name)121 public Student(Id<Student> id, String name) { 122 this.id = id; 123 this.name = name; 124 } 125 } 126 127 @SuppressWarnings("unused") 128 private static class Course<T> { 129 final List<Student> students; 130 private final Id<Course<T>> courseId; 131 private final int numAssignments; 132 private final Assignment<T> assignment; 133 Course()134 private Course() { 135 this(null, 0, null, new ArrayList<Student>()); 136 } 137 Course(Id<Course<T>> courseId, int numAssignments, Assignment<T> assignment, List<Student> players)138 public Course(Id<Course<T>> courseId, int numAssignments, 139 Assignment<T> assignment, List<Student> players) { 140 this.courseId = courseId; 141 this.numAssignments = numAssignments; 142 this.assignment = assignment; 143 this.students = players; 144 } getId()145 public Id<Course<T>> getId() { 146 return courseId; 147 } getStudents()148 List<Student> getStudents() { 149 return students; 150 } 151 } 152 153 @SuppressWarnings("unused") 154 private static class Assignment<T> { 155 private final Id<Assignment<T>> id; 156 private final T data; 157 Assignment()158 private Assignment() { 159 this(null, null); 160 } Assignment(Id<Assignment<T>> id, T data)161 public Assignment(Id<Assignment<T>> id, T data) { 162 this.id = id; 163 this.data = data; 164 } 165 } 166 167 @SuppressWarnings("unused") 168 private static class HistoryCourse { 169 int numClasses; 170 } 171 } 172