gson-comments/gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctional...

214 lines
7.6 KiB
Java
Raw Normal View History

/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson.functional;
import static com.google.common.truth.Truth.assertThat;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Before;
import org.junit.Test;
/**
* Performs some functional tests when Gson is instantiated with some common user defined
* {@link ExclusionStrategy} objects.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public class ExclusionStrategyFunctionalTest {
private static final ExclusionStrategy EXCLUDE_SAMPLE_OBJECT_FOR_TEST = new ExclusionStrategy() {
@Override public boolean shouldSkipField(FieldAttributes f) {
return false;
}
@Override public boolean shouldSkipClass(Class<?> clazz) {
return clazz == SampleObjectForTest.class;
}
};
private SampleObjectForTest src;
@Before
public void setUp() throws Exception {
src = new SampleObjectForTest();
}
@Test
public void testExclusionStrategySerialization() {
2011-04-05 00:48:34 +02:00
Gson gson = createGson(new MyExclusionStrategy(String.class), true);
String json = gson.toJson(src);
assertThat(json).doesNotContain("\"stringField\"");
assertThat(json).doesNotContain("\"annotatedField\"");
assertThat(json).contains("\"longField\"");
}
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
@Test
public void testExclusionStrategySerializationDoesNotImpactDeserialization() {
String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}";
Gson gson = createGson(new MyExclusionStrategy(String.class), true);
SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class);
assertThat(value.annotatedField).isEqualTo(1);
assertThat(value.stringField).isEqualTo("x");
assertThat(value.longField).isEqualTo(2);
}
@Test
public void testExclusionStrategyDeserialization() {
2011-04-05 00:48:34 +02:00
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
JsonObject json = new JsonObject();
json.add("annotatedField", new JsonPrimitive(src.annotatedField + 5));
json.add("stringField", new JsonPrimitive(src.stringField + "blah,blah"));
json.add("longField", new JsonPrimitive(1212311L));
SampleObjectForTest target = gson.fromJson(json, SampleObjectForTest.class);
assertThat(target.longField).isEqualTo(1212311L);
// assert excluded fields are set to the defaults
assertThat(target.annotatedField).isEqualTo(src.annotatedField);
assertThat(target.stringField).isEqualTo(src.stringField);
}
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
@Test
public void testExclusionStrategySerializationDoesNotImpactSerialization() {
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
String json = gson.toJson(src);
assertThat(json).contains("\"stringField\"");
assertThat(json).contains("\"annotatedField\"");
assertThat(json).contains("\"longField\"");
}
@Test
public void testExclusionStrategyWithMode() {
SampleObjectForTest testObj = new SampleObjectForTest(
src.annotatedField + 5, src.stringField + "blah,blah",
src.longField + 655L);
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
JsonObject json = gson.toJsonTree(testObj).getAsJsonObject();
assertThat(json.get("annotatedField").getAsInt()).isEqualTo(testObj.annotatedField);
assertThat(json.get("stringField").getAsString()).isEqualTo(testObj.stringField);
assertThat(json.get("longField").getAsLong()).isEqualTo(testObj.longField);
SampleObjectForTest target = gson.fromJson(json, SampleObjectForTest.class);
assertThat(target.longField).isEqualTo(testObj.longField);
// assert excluded fields are set to the defaults
assertThat(target.annotatedField).isEqualTo(src.annotatedField);
assertThat(target.stringField).isEqualTo(src.stringField);
}
@Test
public void testExcludeTopLevelClassSerialization() {
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST)
.create();
assertThat(gson.toJson(new SampleObjectForTest(), SampleObjectForTest.class)).isEqualTo("null");
}
@Test
public void testExcludeTopLevelClassSerializationDoesNotImpactDeserialization() {
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST)
.create();
String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}";
SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class);
assertThat(value.annotatedField).isEqualTo(1);
assertThat(value.stringField).isEqualTo("x");
assertThat(value.longField).isEqualTo(2);
}
@Test
public void testExcludeTopLevelClassDeserialization() {
Gson gson = new GsonBuilder()
.addDeserializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST)
.create();
String json = "{\"annotatedField\":1,\"stringField\":\"x\",\"longField\":2}";
SampleObjectForTest value = gson.fromJson(json, SampleObjectForTest.class);
assertThat(value).isNull();
}
@Test
public void testExcludeTopLevelClassDeserializationDoesNotImpactSerialization() {
Gson gson = new GsonBuilder()
.addDeserializationExclusionStrategy(EXCLUDE_SAMPLE_OBJECT_FOR_TEST)
.create();
String json = gson.toJson(new SampleObjectForTest(), SampleObjectForTest.class);
assertThat(json).contains("\"stringField\"");
assertThat(json).contains("\"annotatedField\"");
assertThat(json).contains("\"longField\"");
}
2011-04-05 00:48:34 +02:00
private static Gson createGson(ExclusionStrategy exclusionStrategy, boolean serialization) {
GsonBuilder gsonBuilder = new GsonBuilder();
2011-04-05 00:48:34 +02:00
if (serialization) {
2011-04-11 20:44:19 +02:00
gsonBuilder.addSerializationExclusionStrategy(exclusionStrategy);
} else {
2011-04-11 20:44:19 +02:00
gsonBuilder.addDeserializationExclusionStrategy(exclusionStrategy);
}
return gsonBuilder
.serializeNulls()
.create();
}
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
private static @interface Foo {
// Field tag only annotation
}
private static class SampleObjectForTest {
@Foo
private final int annotatedField;
private final String stringField;
private final long longField;
public SampleObjectForTest() {
this(5, "someDefaultValue", 12345L);
}
Down to 22 failing tests. Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
2011-09-11 09:04:56 +02:00
public SampleObjectForTest(int annotatedField, String stringField, long longField) {
this.annotatedField = annotatedField;
this.stringField = stringField;
this.longField = longField;
}
}
private static final class MyExclusionStrategy implements ExclusionStrategy {
private final Class<?> typeToSkip;
private MyExclusionStrategy(Class<?> typeToSkip) {
this.typeToSkip = typeToSkip;
}
@Override public boolean shouldSkipClass(Class<?> clazz) {
return (clazz == typeToSkip);
}
@Override public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(Foo.class) != null;
}
}
}