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; package com.google.gson;
/** /**
* A strategy pattern (see "Design Patterns" written by GoF for some literature on this pattern) * A strategy (or policy) definition that is used to decide whether or not a field or top-level
* definition that is used to decide whether or not a field or top-level class should be serialized * class should be serialized or deserialized as part of the JSON output/input. For serialization,
* (or deserialized) as part of the JSON output/input. * 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 * <p>The following are a few examples that shows how you can use this exclusion mechanism.
* type will be excluded from the output.
* *
* <p><pre class="code"> * <p><strong>Exclude fields and objects based on a particular class type:<strong>
* private static class UserDefinedExclusionStrategy implements ExclusionStrategy { * <pre class="code">
* private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
* private final Class&lt;?&gt; excludedThisClass; * private final Class&lt;?&gt; excludedThisClass;
* *
* UserDefinedExclusionStrategy(Class&lt;?&gt; excludedThisClass) { * public pecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* this.excludedThisClass = excludedThisClass; * this.excludedThisClass = excludedThisClass;
* } * }
* *
@ -40,7 +42,29 @@ package com.google.gson;
* return excludedThisClass.equals(f.getDeclaredClass()); * 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); * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder() * Gson gson = new GsonBuilder()
* .setExclusionStrategies(excludeStrings) * .setExclusionStrategies(excludeStrings)

View File

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

View File

@ -93,6 +93,10 @@ final class ObjectNavigator {
* If a field is null, it does not get visited. * If a field is null, it does not get visited.
*/ */
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
TypeInfo objTypeInfo = new TypeInfo(objTypePair.getType());
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair); boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
if (!visitedWithCustomHandler) { if (!visitedWithCustomHandler) {
Object obj = objTypePair.getObject(); Object obj = objTypePair.getObject();
@ -100,10 +104,7 @@ final class ObjectNavigator {
if (objectToVisit == null) { if (objectToVisit == null) {
return; return;
} }
TypeInfo objTypeInfo = new TypeInfo(objTypePair.getType());
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
visitor.start(objTypePair); visitor.start(objTypePair);
try { try {
if (objTypeInfo.isArray()) { if (objTypeInfo.isArray()) {
@ -141,7 +142,9 @@ final class ObjectNavigator {
Field[] fields = clazz.getDeclaredFields(); Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true); AccessibleObject.setAccessible(fields, true);
for (Field f : fields) { 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 continue; // skip
} else { } else {
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.getType()); 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 { public void testNeverSkipsField() throws Exception {
assertFalse(strategy.shouldSkipField( assertFalse(strategy.shouldSkipField(
new FieldAttributes("".getClass().getFields()[0]))); new FieldAttributes(String.class.getFields()[0])));
} }
} }