Addresses comments in r481 (except for the interface change....leaving FieldAttributes as a class).

Change the exclusion order in ObjectNavigator to exclude a top-level class (if exclusion strategy suggests class should be skipped) even if it is marked with a custom (de)serializer.
This commit is contained in:
Joel Leitch 2009-10-08 20:51:40 +00:00
parent e9c156b016
commit dc5922e703
5 changed files with 45 additions and 17 deletions

View File

@ -17,18 +17,20 @@
package com.google.gson;
/**
* A strategy pattern (see "Design Patterns" written by GoF for some literature on this pattern)
* definition that is used to decide whether or not a field or top-level class should be serialized
* (or deserialized) as part of the JSON output/input.
* A strategy (or policy) definition that is used to decide whether or not a field or top-level
* class should be serialized or deserialized as part of the JSON output/input. For serialization,
* if the {@link this#shouldSkipClass(Class)} method returns false then that class or field type
* will not be part of the JSON output. For deserialization, if {@link this#shouldSkipClass(Class)}
* returns false, then it will not be set as part of the Java object structure.
*
* <p>The following example show an implementation of an {@code ExclusionStrategy} where a specific
* type will be excluded from the output.
* <p>The following are a few examples that shows how you can use this exclusion mechanism.
*
* <p><pre class="code">
* private static class UserDefinedExclusionStrategy implements ExclusionStrategy {
* <p><strong>Exclude fields and objects based on a particular class type:<strong>
* <pre class="code">
* private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
* private final Class&lt;?&gt; excludedThisClass;
*
* UserDefinedExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* public pecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* this.excludedThisClass = excludedThisClass;
* }
*
@ -40,7 +42,29 @@ package com.google.gson;
* return excludedThisClass.equals(f.getDeclaredClass());
* }
* }
* </pre>
*
* <p><strong>Excludes fields and objects based on a particular annotation:</strong>
* <pre class="code">
* public &#64interface FooAnnotation {
* // some implementation here
* }
*
* // Excludes any field (or class) that is tagged with an "&#64FooAnnotation"
* private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {
* public boolean shouldSkipClass(Class&lt;?&gt; clazz) {
* return clazz.getAnnotation(FooAnnotation.class) != null;
* }
*
* public boolean shouldSkipField(FieldAttributes f) {
* return f.getAnnotation(FooAnnotation.class) != null;
* }
* }
* </pre>
*
* <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
* the {@code GsonBuilder} is required. The following is an example of how you can use the
* {@code GsonBuilder} to configure Gson to use one of the above sample
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder()
* .setExclusionStrategies(excludeStrings)

View File

@ -115,8 +115,9 @@ final class FieldAttributes {
}
/**
* This is exposed internally only for the
* @return
* This is exposed internally only for the removing synthetic fields from the JSON output.
*
* @return true if the field is synthetic; otherwise false
*/
boolean isSynthetic() {
return field.isSynthetic();

View File

@ -93,6 +93,10 @@ final class ObjectNavigator {
* If a field is null, it does not get visited.
*/
public void accept(Visitor visitor) {
TypeInfo objTypeInfo = new TypeInfo(objTypePair.getType());
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
if (!visitedWithCustomHandler) {
Object obj = objTypePair.getObject();
@ -100,10 +104,7 @@ final class ObjectNavigator {
if (objectToVisit == null) {
return;
}
TypeInfo objTypeInfo = new TypeInfo(objTypePair.getType());
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
visitor.start(objTypePair);
try {
if (objTypeInfo.isArray()) {
@ -141,7 +142,9 @@ final class ObjectNavigator {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
if (exclusionStrategy.shouldSkipField(new FieldAttributes(f))) {
FieldAttributes fieldAttributes = new FieldAttributes(f);
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
continue; // skip
} else {
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.getType());

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 Google Inc.
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -38,6 +38,6 @@ public class NullExclusionStrategyTest extends TestCase {
public void testNeverSkipsField() throws Exception {
assertFalse(strategy.shouldSkipField(
new FieldAttributes("".getClass().getFields()[0])));
new FieldAttributes(String.class.getFields()[0])));
}
}