Add the ability to configure Gson to exclude serializing and deserializing of all "Inner Classes".

This commit is contained in:
Joel Leitch 2008-12-28 02:00:31 +00:00
parent 73117fe652
commit 54a480774d
7 changed files with 223 additions and 8 deletions

View File

@ -0,0 +1,39 @@
/*
* 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;
import java.lang.reflect.Field;
/**
* Strategy for excluding anonymous and local classes.
*
* @author Joel Leitch
*/
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(Field f) {
return isAnonymousOrLocal(f.getType());
}
public boolean shouldSkipClass(Class<?> clazz) {
return isAnonymousOrLocal(clazz);
}
private boolean isAnonymousOrLocal(Class<?> clazz) {
return clazz.isAnonymousClass() || clazz.isLocalClass();
}
}

View File

@ -182,7 +182,7 @@ public final class Gson {
private static ExclusionStrategy createExclusionStrategy(double version) { private static ExclusionStrategy createExclusionStrategy(double version) {
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>(); List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(new InnerClassExclusionStrategy()); strategies.add(new AnonymousAndLocalClassExclusionStrategy());
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY); strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
if (version != VersionConstants.IGNORE_VERSIONS) { if (version != VersionConstants.IGNORE_VERSIONS) {
strategies.add(new VersionExclusionStrategy(version)); strategies.add(new VersionExclusionStrategy(version));

View File

@ -53,6 +53,8 @@ public final class GsonBuilder {
private double ignoreVersionsAfter; private double ignoreVersionsAfter;
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy; private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
private boolean serializeInnerClasses;
private final AnonymousAndLocalClassExclusionStrategy anonAndLocalClassExclusionStrategy;
private final InnerClassExclusionStrategy innerClassExclusionStrategy; private final InnerClassExclusionStrategy innerClassExclusionStrategy;
private boolean excludeFieldsWithoutExposeAnnotation; private boolean excludeFieldsWithoutExposeAnnotation;
private JsonFormatter formatter; private JsonFormatter formatter;
@ -75,6 +77,8 @@ public final class GsonBuilder {
public GsonBuilder() { public GsonBuilder() {
// setup default values // setup default values
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS; ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
serializeInnerClasses = true;
anonAndLocalClassExclusionStrategy = new AnonymousAndLocalClassExclusionStrategy();
innerClassExclusionStrategy = new InnerClassExclusionStrategy(); innerClassExclusionStrategy = new InnerClassExclusionStrategy();
modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY; modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY;
excludeFieldsWithoutExposeAnnotation = false; excludeFieldsWithoutExposeAnnotation = false;
@ -140,6 +144,21 @@ public final class GsonBuilder {
this.serializeNulls = true; this.serializeNulls = true;
return this; return this;
} }
/**
* Configures Gson to include or exclude inner classes
*
* @param modifiers the field modifiers. You must use the modifiers specified in the
* {@link java.lang.reflect.Modifier} class. For example,
* {@link java.lang.reflect.Modifier#TRANSIENT},
* {@link java.lang.reflect.Modifier#STATIC}.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
*/
public GsonBuilder serializeInnerClasses(boolean value) {
serializeInnerClasses = value;
return this;
}
/** /**
* Configures Gson to apply a specific naming policy to an object's field during serialization * Configures Gson to apply a specific naming policy to an object's field during serialization
* and deserialization. * and deserialization.
@ -357,8 +376,12 @@ public final class GsonBuilder {
*/ */
public Gson create() { public Gson create() {
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>(); List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(innerClassExclusionStrategy);
strategies.add(modifierBasedExclusionStrategy); strategies.add(modifierBasedExclusionStrategy);
strategies.add(anonAndLocalClassExclusionStrategy);
if (!serializeInnerClasses) {
strategies.add(innerClassExclusionStrategy);
}
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) { if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
strategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); strategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
} }

View File

@ -17,23 +17,28 @@
package com.google.gson; package com.google.gson;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/** /**
* Strategy for excluding inner classes. * Strategy for excluding inner classes.
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
final class InnerClassExclusionStrategy implements ExclusionStrategy { public class InnerClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(Field f) { public boolean shouldSkipField(Field f) {
return isAnonymousOrLocal(f.getType()); return isInnerClass(f.getType());
} }
public boolean shouldSkipClass(Class<?> clazz) { public boolean shouldSkipClass(Class<?> clazz) {
return isAnonymousOrLocal(clazz); return isInnerClass(clazz);
} }
private boolean isAnonymousOrLocal(Class<?> clazz) { private boolean isInnerClass(Class<?> clazz) {
return clazz.isAnonymousClass() || clazz.isLocalClass(); return clazz.isMemberClass() && !isStatic(clazz);
}
private boolean isStatic(Class<?> clazz) {
return (clazz.getModifiers() & Modifier.STATIC) != 0;
} }
} }

View File

@ -43,7 +43,7 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
public JsonElement serialize(Object src, Type typeOfSrc) { public JsonElement serialize(Object src, Type typeOfSrc) {
ObjectNavigator on = factory.create(src, typeOfSrc); ObjectNavigator on = factory.create(src, typeOfSrc);
JsonSerializationVisitor visitor = JsonSerializationVisitor visitor =
new JsonSerializationVisitor(factory, serializeNulls, serializers, this); new JsonSerializationVisitor(factory, serializeNulls, serializers, this);
on.accept(visitor); on.accept(visitor);
return visitor.getJsonElement(); return visitor.getJsonElement();
} }

View File

@ -0,0 +1,67 @@
/*
* 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;
import java.lang.reflect.Field;
import junit.framework.TestCase;
/**
* Unit test for the {@link InnerClassExclusionStrategy} class.
*
* @author Joel Leitch
*/
public class InnerClassExclusionStrategyTest extends TestCase {
public InnerClass innerClass;
public StaticNestedClass staticNestedClass;
private InnerClassExclusionStrategy strategy;
@Override
protected void setUp() throws Exception {
super.setUp();
innerClass = new InnerClass();
staticNestedClass = new StaticNestedClass();
strategy = new InnerClassExclusionStrategy();
}
public void testExcludeInnerClassObject() throws Exception {
Class<?> clazz = innerClass.getClass();
assertTrue(strategy.shouldSkipClass(clazz));
}
public void testExcludeInnerClassField() throws Exception {
Field f = getClass().getField("innerClass");
assertTrue(strategy.shouldSkipField(f));
}
public void testIncludeStaticNestedClassObject() throws Exception {
Class<?> clazz = staticNestedClass.getClass();
assertFalse(strategy.shouldSkipClass(clazz));
}
public void testIncludeStaticNestedClassField() throws Exception {
Field f = getClass().getField("staticNestedClass");
assertFalse(strategy.shouldSkipField(f));
}
class InnerClass {
}
static class StaticNestedClass {
}
}

View File

@ -0,0 +1,81 @@
/*
* 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 com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import junit.framework.TestCase;
/**
* Performs some functional testing to ensure GSON infrastructure properly serializes/deserializes
* fields that either should or should not be included in the output based on the GSON
* configuration.
*
* @author Joel Leitch
*/
public class FieldExclusionTest extends TestCase {
private static final String VALUE = "blah_1234";
public void testDefaultInnerClassExclusion() throws Exception {
Gson gson = new Gson();
TestInnerClass target = new TestInnerClass(VALUE);
String result = gson.toJson(target);
assertEquals(target.toJson(), result);
gson = new GsonBuilder().create();
target = new TestInnerClass(VALUE);
result = gson.toJson(target);
assertEquals(target.toJson(), result);
}
public void testInnerClassExclusion() throws Exception {
Gson gson = new GsonBuilder().serializeInnerClasses(false).create();
TestInnerClass target = new TestInnerClass(VALUE);
String result = gson.toJson(target);
assertEquals("", result);
}
public void testDefaultNestedStaticClassIncluded() throws Exception {
Gson gson = new Gson();
TestInnerClass target = new TestInnerClass(VALUE);
String result = gson.toJson(target);
assertEquals(target.toJson(), result);
gson = new GsonBuilder().create();
target = new TestInnerClass(VALUE);
result = gson.toJson(target);
assertEquals(target.toJson(), result);
}
private class TestInnerClass extends TestStaticNestedClass {
public TestInnerClass(String value) {
super(value);
}
}
private static class TestStaticNestedClass {
private final String value;
public TestStaticNestedClass(String value) {
this.value = value;
}
public String toJson() {
return "{\"value\":\"" + value + "\"}";
}
}
}