Provide a means to add serialization or deserialization specific exclusion strategies.

This commit is contained in:
Joel Leitch 2011-02-04 03:09:41 +00:00
parent ea48a1debf
commit 114633fbf9
26 changed files with 201 additions and 464 deletions

View File

@ -21,13 +21,13 @@ package com.google.gson;
*
* @author Joel Leitch
*/
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy2 {
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
return isAnonymousOrLocal(f.getDeclaredClass());
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return isAnonymousOrLocal(clazz);
}

View File

@ -19,31 +19,31 @@ package com.google.gson;
import java.util.Collection;
/**
* A wrapper class used to collect numerous {@link ExclusionStrategy2} objects
* A wrapper class used to collect numerous {@link ExclusionStrategy} objects
* and perform a short-circuited OR operation.
*
* @author Joel Leitch
*/
final class DisjunctionExclusionStrategy implements ExclusionStrategy2 {
private final Collection<ExclusionStrategy2> strategies;
final class DisjunctionExclusionStrategy implements ExclusionStrategy {
private final Collection<ExclusionStrategy> strategies;
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy2> strategies) {
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
Preconditions.checkNotNull(strategies);
this.strategies = strategies;
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
for (ExclusionStrategy2 strategy : strategies) {
if (strategy.shouldSkipField(f, mode)) {
public boolean shouldSkipField(FieldAttributes f) {
for (ExclusionStrategy strategy : strategies) {
if (strategy.shouldSkipField(f)) {
return true;
}
}
return false;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
for (ExclusionStrategy2 strategy : strategies) {
if (strategy.shouldSkipClass(clazz, mode)) {
public boolean shouldSkipClass(Class<?> clazz) {
for (ExclusionStrategy strategy : strategies) {
if (strategy.shouldSkipClass(clazz)) {
return true;
}
}

View File

@ -71,6 +71,10 @@ package com.google.gson;
* .setExclusionStrategies(excludeStrings)
* .create();
* </pre>
*
* <p>For certain model classes, you may only want to serialize a field, but exclude it for
* deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;
* however, you would register it with the
*
* @author Inderjeet Singh
* @author Joel Leitch
@ -78,9 +82,7 @@ package com.google.gson;
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
*
* @since 1.4
* @deprecated use the more powerful {@link ExclusionStrategy2} instead.
*/
@Deprecated
public interface ExclusionStrategy {
/**

View File

@ -1,125 +0,0 @@
/*
* Copyright (C) 2011 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;
/**
* 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 #shouldSkipClass(Class, Mode)} method returns false then that class or field
* type will not be part of the JSON output. For deserialization, if
* {@link #shouldSkipClass(Class, , Context)} returns false, then it will not be set as part of
* the Java object structure.
*
* <p>The following are a few examples that shows how you can use this exclusion mechanism.
*
* <p><strong>Exclude fields and objects based on a particular class type for both serialization
* and deserialization:</strong>
* <pre class="code">
* public class SpecificClassExclusionStrategy implements ExclusionStrategy2 {
* private final Class&lt;?&gt; excludedThisClass;
*
* public SpecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* this.excludedThisClass = excludedThisClass;
* }
*
* public boolean shouldSkipClass(Class&lt;?&gt; clazz, Context context) {
* return excludedThisClass.equals(clazz);
* }
*
* public boolean shouldSkipField(FieldAttributes f, Context context) {
* return excludedThisClass.equals(f.getDeclaredClass());
* }
* }
* </pre>
*
* <p><strong>Excludes fields and objects based on a particular annotation for both serialization
* and deserialization:</strong>
* <pre class="code">
* public &#64interface FooAnnotation {
* // some implementation here
* }
*
* // Excludes any field (or class) that is tagged with an "&#64FooAnnotation"
* public class FooAnnotationExclusionStrategy implements ExclusionStrategy2 {
* public boolean shouldSkipClass(Class&lt;?&gt; clazz, Context context) {
* return clazz.getAnnotation(FooAnnotation.class) != null;
* }
*
* public boolean shouldSkipField(FieldAttributes f, Context context) {
* return f.getAnnotation(FooAnnotation.class) != null;
* }
* }
* </pre>
*
* <p><strong>Exclude fields and objects based on a particular class type for serialization
* only:</strong>
* <pre class="code">
* public class SpecificClassExclusionStrategy implements ExclusionStrategy2 {
* private final Class&lt;?&gt; excludedThisClass;
*
* public SpecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* this.excludedThisClass = excludedThisClass;
* }
*
* public boolean shouldSkipClass(Class&lt;?&gt; clazz, Context context) {
* if (context == Context.SERIALIZE) {
* return excludedThisClass.equals(clazz);
* } else {
* return false;
* }
* }
*
* public boolean shouldSkipField(FieldAttributes f, Context context) {
* if (context == Context.SERIALIZE) {
* return excludedThisClass.equals(f.getDeclaredClass());
* } else {
* return false;
* }
* }
* }
* </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:
* <pre class="code">
* ExclusionStrategy2 excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder()
* .setExclusionStrategies(excludeStrings)
* .create();
* </pre>
*
* @author Joel Leitch
*
* @since 1.7
*/
public interface ExclusionStrategy2 {
/**
* @param f the field object that is under test
* @param mode the current mode the Gson is running in
* @return true if the field should be ignored; otherwise false
*/
public boolean shouldSkipField(FieldAttributes f, Mode mode);
/**
* @param clazz the class object that is under test
* @param mode the current mode the Gson is running in
* @return true if the class should be ignored; otherwise false
*/
public boolean shouldSkipClass(Class<?> clazz, Mode mode);
}

View File

@ -23,23 +23,16 @@ import com.google.gson.annotations.Expose;
*
* @author Joel Leitch
*/
public class ExposeAnnotationExclusionStrategy implements ExclusionStrategy2 {
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
Expose annotation = f.getAnnotation(Expose.class);
if (annotation == null) {
return true;
}
if (mode == Mode.SERIALIZE) {
return !annotation.serialize();
} else if (mode == Mode.DESERIALIZE) {
return !annotation.deserialize();
}
return false;
return !annotation.deserialize();
}
}

View File

@ -16,24 +16,23 @@
package com.google.gson;
import com.google.gson.annotations.Expose;
/**
* Adapts the old {@link ExclusionStrategy} into the newer {@link ExclusionStrategy2} type.
* Excludes fields that do not have the {@link Expose} annotation
*
* @author Joel Leitch
*/
class ExclusionStrategy2Adapter implements ExclusionStrategy2 {
private final ExclusionStrategy strategy;
public ExclusionStrategy2Adapter(ExclusionStrategy strategy) {
Preconditions.checkNotNull(strategy);
this.strategy = strategy;
public class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
return strategy.shouldSkipClass(clazz);
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
return strategy.shouldSkipField(f);
public boolean shouldSkipField(FieldAttributes f) {
Expose annotation = f.getAnnotation(Expose.class);
if (annotation == null) {
return true;
}
return !annotation.serialize();
}
}

View File

@ -90,11 +90,12 @@ public final class Gson {
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
private static final ExclusionStrategy2 DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
private final ExclusionStrategy2 exclusionStrategy;
private final ExclusionStrategy deserializationExclusionStrategy;
private final ExclusionStrategy serializationExclusionStrategy;
private final FieldNamingStrategy2 fieldNamingPolicy;
private final MappedObjectConstructor objectConstructor;
@ -144,18 +145,20 @@ public final class Gson {
* </ul>
*/
public Gson() {
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
false, DefaultTypeAdapters.getAllDefaultSerializers(),
DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
}
Gson(ExclusionStrategy2 exclusionStrategy, FieldNamingStrategy2 fieldNamingPolicy,
Gson(ExclusionStrategy deserializationExclusionStrategy,
ExclusionStrategy serializationExclusionStrategy, FieldNamingStrategy2 fieldNamingPolicy,
MappedObjectConstructor objectConstructor, boolean serializeNulls,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
this.exclusionStrategy = exclusionStrategy;
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
this.serializationExclusionStrategy = serializationExclusionStrategy;
this.fieldNamingPolicy = fieldNamingPolicy;
this.objectConstructor = objectConstructor;
this.serializeNulls = serializeNulls;
@ -166,12 +169,12 @@ public final class Gson {
this.prettyPrinting = prettyPrinting;
}
private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy2 strategy) {
private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) {
return new ObjectNavigatorFactory(strategy, fieldNamingPolicy);
}
private static ExclusionStrategy2 createExclusionStrategy() {
List<ExclusionStrategy2> strategies = new LinkedList<ExclusionStrategy2>();
private static ExclusionStrategy createExclusionStrategy() {
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
@ -219,7 +222,7 @@ public final class Gson {
return JsonNull.createJsonNull();
}
JsonSerializationContextDefault context = new JsonSerializationContextDefault(
createDefaultObjectNavigatorFactory(exclusionStrategy), serializeNulls, serializers);
createDefaultObjectNavigatorFactory(serializationExclusionStrategy), serializeNulls, serializers);
return context.serialize(src, typeOfSrc, true);
}
@ -549,8 +552,8 @@ public final class Gson {
return null;
}
JsonDeserializationContext context = new JsonDeserializationContextDefault(
createDefaultObjectNavigatorFactory(exclusionStrategy), deserializers,
objectConstructor);
createDefaultObjectNavigatorFactory(deserializationExclusionStrategy),
deserializers, objectConstructor);
T target = (T) context.deserialize(json, typeOfT);
return target;
}

View File

@ -18,11 +18,12 @@ package com.google.gson;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.Collection;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
@ -54,11 +55,17 @@ import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
public final class GsonBuilder {
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
new InnerClassExclusionStrategy();
private static final ExposeAnnotationExclusionStrategy exposeAnnotationExclusionStrategy =
new ExposeAnnotationExclusionStrategy();
private static final ExposeAnnotationDeserializationExclusionStrategy
exposeAnnotationDeserializationExclusionStrategy =
new ExposeAnnotationDeserializationExclusionStrategy();
private static final ExposeAnnotationSerializationExclusionStrategy
exposeAnnotationSerializationExclusionStrategy =
new ExposeAnnotationSerializationExclusionStrategy();
private final Collection<ExclusionStrategy2> exclusionStrategies =
new HashSet<ExclusionStrategy2>();
private final Set<ExclusionStrategy> serializeExclusionStrategies =
new HashSet<ExclusionStrategy>();
private final Set<ExclusionStrategy> deserializeExclusionStrategies =
new HashSet<ExclusionStrategy>();
private double ignoreVersionsAfter;
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
@ -86,8 +93,10 @@ public final class GsonBuilder {
*/
public GsonBuilder() {
// add default exclusion strategies
exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
deserializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
serializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
serializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
// setup default values
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
@ -248,32 +257,32 @@ public final class GsonBuilder {
* @param strategies the set of strategy object to apply during object (de)serialization.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.4
* @deprecated convert your {@code strategies} to {@link ExclusionStrategy2} and use the
* {@link #setExclusionStrategies(ExclusionStrategy2...) method instead.
*/
@Deprecated
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
for (ExclusionStrategy strategy : strategies) {
exclusionStrategies.add(new ExclusionStrategy2Adapter(strategy));
}
List<ExclusionStrategy> strategyList = Arrays.asList(strategies);
serializeExclusionStrategies.addAll(strategyList);
deserializeExclusionStrategies.addAll(strategyList);
return this;
}
/**
* Configures Gson to apply a set of exclusion strategies during both serialization and
* Configures Gson to apply a set of exclusion strategies during either serialization or
* deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
* This means that if one of the {@code strategies} suggests that a field (or class) should be
* skipped in the current mode then that field (or object) is skipped during the particular Gson
* mode.
* skipped then that field (or object) is skipped during either serialization or deserialization
* depending on the {@code mode} that is passed into this method.
*
* @param strategies the set of strategy object to apply during object (de)serialization.
* @param strategies the set of strategy object to apply during the {@code mode}.
* @param the mode of Gson (either serialization or deserialization) as to when the
* {@code strategies} should be applied.
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7
*/
public GsonBuilder setExclusionStrategies(ExclusionStrategy2... strategies) {
for (ExclusionStrategy2 strategy : strategies) {
exclusionStrategies.add(strategy);
}
public GsonBuilder setExclusionStrategies(Mode mode, ExclusionStrategy... strategies) {
Preconditions.checkNotNull(mode);
Set<ExclusionStrategy> strategySet = (mode == Mode.SERIALIZE)
? serializeExclusionStrategies : deserializeExclusionStrategies;
strategySet.addAll(Arrays.asList(strategies));
return this;
}
@ -519,20 +528,27 @@ public final class GsonBuilder {
* @return an instance of Gson configured with the options currently set in this builder
*/
public Gson create() {
List<ExclusionStrategy2> strategies =
new LinkedList<ExclusionStrategy2>(exclusionStrategies);
strategies.add(modifierBasedExclusionStrategy);
List<ExclusionStrategy> deserializationStrategies =
new LinkedList<ExclusionStrategy>(deserializeExclusionStrategies);
List<ExclusionStrategy> serializationStrategies =
new LinkedList<ExclusionStrategy>(serializeExclusionStrategies);
deserializationStrategies.add(modifierBasedExclusionStrategy);
serializationStrategies.add(modifierBasedExclusionStrategy);
if (!serializeInnerClasses) {
strategies.add(innerClassExclusionStrategy);
deserializationStrategies.add(innerClassExclusionStrategy);
serializationStrategies.add(innerClassExclusionStrategy);
}
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
strategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
VersionExclusionStrategy versionExclusionStrategy =
new VersionExclusionStrategy(ignoreVersionsAfter);
deserializationStrategies.add(versionExclusionStrategy);
serializationStrategies.add(versionExclusionStrategy);
}
if (excludeFieldsWithoutExposeAnnotation) {
strategies.add(exposeAnnotationExclusionStrategy);
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
}
ExclusionStrategy2 exclusionStrategy = new DisjunctionExclusionStrategy(strategies);
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers =
DefaultTypeAdapters.DEFAULT_HIERARCHY_SERIALIZERS.copyOf();
@ -558,7 +574,9 @@ public final class GsonBuilder {
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
Gson gson = new Gson(exclusionStrategy, fieldNamingPolicy, objConstructor, serializeNulls,
Gson gson = new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
new DisjunctionExclusionStrategy(serializationStrategies),
fieldNamingPolicy, objConstructor, serializeNulls,
customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars,
prettyPrinting);
return gson;

View File

@ -23,13 +23,13 @@ import java.lang.reflect.Modifier;
*
* @author Joel Leitch
*/
class InnerClassExclusionStrategy implements ExclusionStrategy2 {
class InnerClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
return isInnerClass(f.getDeclaredClass());
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return isInnerClass(clazz);
}

View File

@ -58,10 +58,6 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
}
return target;
}
public Mode getMode() {
return Mode.DESERIALIZE;
}
protected abstract T constructTarget();

View File

@ -47,10 +47,6 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
public Object getTarget() {
return null;
}
public Mode getMode() {
return Mode.SERIALIZE;
}
public void start(ObjectTypePair node) {
if (node == null) {

View File

@ -26,7 +26,7 @@ import java.util.HashSet;
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class ModifierBasedExclusionStrategy implements ExclusionStrategy2 {
final class ModifierBasedExclusionStrategy implements ExclusionStrategy {
private final Collection<Integer> modifiers;
public ModifierBasedExclusionStrategy(int... modifiers) {
@ -38,7 +38,7 @@ final class ModifierBasedExclusionStrategy implements ExclusionStrategy2 {
}
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
for (int modifier : modifiers) {
if (f.hasModifier(modifier)) {
return true;
@ -47,7 +47,7 @@ final class ModifierBasedExclusionStrategy implements ExclusionStrategy2 {
return false;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}

View File

@ -24,13 +24,13 @@ package com.google.gson;
*
* @author Joel Leitch
*/
final class NullExclusionStrategy implements ExclusionStrategy2 {
final class NullExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
return false;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}

View File

@ -75,11 +75,9 @@ final class ObjectNavigator {
* Retrieve the current target
*/
Object getTarget();
Mode getMode();
}
private final ExclusionStrategy2 exclusionStrategy;
private final ExclusionStrategy exclusionStrategy;
private final ObjectTypePair objTypePair;
/**
@ -89,7 +87,7 @@ final class ObjectNavigator {
* the concrete strategy object to be used to filter out fields of an
* object.
*/
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy2 exclusionStrategy) {
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
Preconditions.checkNotNull(exclusionStrategy);
this.objTypePair = objTypePair;
@ -101,7 +99,7 @@ final class ObjectNavigator {
* does not get visited.
*/
public void accept(Visitor visitor) {
if (exclusionStrategy.shouldSkipClass(Types.getRawType(objTypePair.type), visitor.getMode())) {
if (exclusionStrategy.shouldSkipClass(Types.getRawType(objTypePair.type))) {
return;
}
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
@ -145,13 +143,12 @@ final class ObjectNavigator {
}
private void navigateClassFields(Object obj, Class<?> clazz, Visitor visitor) {
Mode mode = visitor.getMode();
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
if (exclusionStrategy.shouldSkipField(fieldAttributes, mode)
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass(), mode)) {
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
continue; // skip
}
Type declaredTypeOfField = getTypeInfoForField(f, objTypePair.type);

View File

@ -24,7 +24,7 @@ package com.google.gson;
* @author Joel Leitch
*/
final class ObjectNavigatorFactory {
private final ExclusionStrategy2 strategy;
private final ExclusionStrategy strategy;
private final FieldNamingStrategy2 fieldNamingPolicy;
/**
@ -36,7 +36,7 @@ final class ObjectNavigatorFactory {
* @param fieldNamingPolicy the naming policy that should be applied to field
* names
*/
public ObjectNavigatorFactory(ExclusionStrategy2 strategy, FieldNamingStrategy2 fieldNamingPolicy) {
public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) {
Preconditions.checkNotNull(fieldNamingPolicy);
this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy);
this.fieldNamingPolicy = fieldNamingPolicy;

View File

@ -26,18 +26,18 @@ package com.google.gson;
*
* @since 1.4
*/
class SyntheticFieldExclusionStrategy implements ExclusionStrategy2 {
class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
private final boolean skipSyntheticFields;
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
this.skipSyntheticFields = skipSyntheticFields;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
return skipSyntheticFields && f.isSynthetic();
}

View File

@ -25,7 +25,7 @@ import com.google.gson.annotations.Until;
*
* @author Joel Leitch
*/
final class VersionExclusionStrategy implements ExclusionStrategy2 {
final class VersionExclusionStrategy implements ExclusionStrategy {
private final double version;
public VersionExclusionStrategy(double version) {
@ -33,11 +33,11 @@ final class VersionExclusionStrategy implements ExclusionStrategy2 {
this.version = version;
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
public boolean shouldSkipField(FieldAttributes f) {
return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class));
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
public boolean shouldSkipClass(Class<?> clazz) {
return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class));
}

View File

@ -16,11 +16,11 @@
package com.google.gson;
import junit.framework.TestCase;
import java.util.LinkedList;
import java.util.List;
import junit.framework.TestCase;
/**
* Unit tests for the {@link DisjunctionExclusionStrategy} class.
*
@ -28,38 +28,38 @@ import junit.framework.TestCase;
*/
public class DisjunctionExclusionStrategyTest extends TestCase {
private static final ExclusionStrategy2 FALSE_STRATEGY =
new MockExclusionStrategy2(false, false, null);
private static final ExclusionStrategy2 TRUE_STRATEGY =
new MockExclusionStrategy2(true, true, null);
private static final ExclusionStrategy FALSE_STRATEGY =
new MockExclusionStrategy(false, false);
private static final ExclusionStrategy TRUE_STRATEGY =
new MockExclusionStrategy(true, true);
private static final Class<?> CLAZZ = String.class;
private static final FieldAttributes FIELD = new FieldAttributes(CLAZZ, CLAZZ.getFields()[0]);
public void testBadInstantiation() throws Exception {
try {
List<ExclusionStrategy2> constructorParam = null;
List<ExclusionStrategy> constructorParam = null;
new DisjunctionExclusionStrategy(constructorParam);
fail("Should throw an exception");
} catch (IllegalArgumentException expected) { }
}
public void testSkipFieldsWithMixedTrueAndFalse() throws Exception {
List<ExclusionStrategy2> strategies = new LinkedList<ExclusionStrategy2>();
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(FALSE_STRATEGY);
strategies.add(TRUE_STRATEGY);
DisjunctionExclusionStrategy strategy = new DisjunctionExclusionStrategy(strategies);
assertTrue(strategy.shouldSkipClass(CLAZZ, Mode.SERIALIZE));
assertTrue(strategy.shouldSkipField(FIELD, Mode.SERIALIZE));
assertTrue(strategy.shouldSkipClass(CLAZZ));
assertTrue(strategy.shouldSkipField(FIELD));
}
public void testSkipFieldsWithFalseOnly() throws Exception {
List<ExclusionStrategy2> strategies = new LinkedList<ExclusionStrategy2>();
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(FALSE_STRATEGY);
DisjunctionExclusionStrategy strategy = new DisjunctionExclusionStrategy(strategies);
assertFalse(strategy.shouldSkipClass(CLAZZ, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipField(FIELD, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipClass(CLAZZ));
assertFalse(strategy.shouldSkipField(FIELD));
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2011 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 ExclusionStrategy2Adapter} class.
*
* @author Joel Leitch
*/
public class ExclusionStrategy2AdapterTest extends TestCase {
public void testConstruction() throws Exception {
try {
new ExclusionStrategy2Adapter(null);
fail();
} catch (IllegalArgumentException expected) {}
}
public void testAdapterDoesSameForBothModes() throws Exception {
ExclusionStrategy2Adapter adapter =
new ExclusionStrategy2Adapter(new MockExclusionStrategy(true, false));
assertTrue(adapter.shouldSkipClass(String.class, Mode.DESERIALIZE));
assertTrue(adapter.shouldSkipClass(String.class, Mode.SERIALIZE));
Field f = String.class.getFields()[0];
assertFalse(adapter.shouldSkipField(new FieldAttributes(String.class, f), Mode.DESERIALIZE));
assertFalse(adapter.shouldSkipField(new FieldAttributes(String.class, f), Mode.SERIALIZE));
}
}

View File

@ -16,59 +16,61 @@
package com.google.gson;
import java.lang.reflect.Field;
import com.google.gson.annotations.Expose;
import junit.framework.TestCase;
import java.lang.reflect.Field;
/**
* Unit tests for the {@link ExposeAnnotationExclusionStrategy} class.
* Unit tests for the {@link ExposeAnnotationSerializationExclusionStrategy} class.
*
* @author Joel Leitch
*/
public class ExposeAnnotationExclusionStrategyTest extends TestCase {
private ExposeAnnotationExclusionStrategy strategy;
private ExposeAnnotationDeserializationExclusionStrategy deserializationStrategy;
private ExposeAnnotationSerializationExclusionStrategy serializationStrategy;
@Override
protected void setUp() throws Exception {
super.setUp();
strategy = new ExposeAnnotationExclusionStrategy();
deserializationStrategy = new ExposeAnnotationDeserializationExclusionStrategy();
serializationStrategy = new ExposeAnnotationSerializationExclusionStrategy();
}
public void testNeverSkipClasses() throws Exception {
assertFalse(strategy.shouldSkipClass(MockObject.class, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipClass(MockObject.class, Mode.SERIALIZE));
assertFalse(deserializationStrategy.shouldSkipClass(MockObject.class));
assertFalse(serializationStrategy.shouldSkipClass(MockObject.class));
}
public void testSkipNonAnnotatedFields() throws Exception {
FieldAttributes f = createFieldAttributes("hiddenField");
assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipField(f, Mode.SERIALIZE));
assertTrue(deserializationStrategy.shouldSkipField(f));
assertTrue(serializationStrategy.shouldSkipField(f));
}
public void testSkipExplicitlySkippedFields() throws Exception {
FieldAttributes f = createFieldAttributes("explicitlyHiddenField");
assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipField(f, Mode.SERIALIZE));
assertTrue(deserializationStrategy.shouldSkipField(f));
assertTrue(serializationStrategy.shouldSkipField(f));
}
public void testNeverSkipExposedAnnotatedFields() throws Exception {
FieldAttributes f = createFieldAttributes("exposedField");
assertFalse(strategy.shouldSkipField(f, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE));
assertFalse(deserializationStrategy.shouldSkipField(f));
assertFalse(serializationStrategy.shouldSkipField(f));
}
public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception {
FieldAttributes f = createFieldAttributes("explicitlyExposedField");
assertFalse(strategy.shouldSkipField(f, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE));
assertFalse(deserializationStrategy.shouldSkipField(f));
assertFalse(serializationStrategy.shouldSkipField(f));
}
public void testDifferentSerializeAndDeserializeField() throws Exception {
FieldAttributes f = createFieldAttributes("explicitlyDifferentModeField");
assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE));
assertTrue(deserializationStrategy.shouldSkipField(f));
assertFalse(serializationStrategy.shouldSkipField(f));
}
private static FieldAttributes createFieldAttributes(String fieldName) throws Exception {

View File

@ -35,11 +35,11 @@ import com.google.gson.common.TestTypes.ClassWithNoFields;
public class FunctionWithInternalDependenciesTest extends TestCase {
public void testAnonymousLocalClassesSerialization() throws Exception {
LinkedList<ExclusionStrategy2> strategies = new LinkedList<ExclusionStrategy2>();
LinkedList<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(new SyntheticFieldExclusionStrategy(true));
strategies.add(new ModifierBasedExclusionStrategy(Modifier.TRANSIENT, Modifier.STATIC));
ExclusionStrategy2 exclusionStrategy = new DisjunctionExclusionStrategy(strategies);
Gson gson = new Gson(exclusionStrategy, Gson.DEFAULT_NAMING_POLICY,
ExclusionStrategy exclusionStrategy = new DisjunctionExclusionStrategy(strategies);
Gson gson = new Gson(exclusionStrategy, exclusionStrategy, Gson.DEFAULT_NAMING_POLICY,
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
false, DefaultTypeAdapters.getDefaultSerializers(),
DefaultTypeAdapters.getDefaultDeserializers(), Gson.DEFAULT_JSON_NON_EXECUTABLE, true,
@ -48,32 +48,4 @@ public class FunctionWithInternalDependenciesTest extends TestCase {
// empty anonymous class
}));
}
// TODO(Joel): Move this to some other functional test once exclusion policies are
// available to the public
public void testUserDefinedExclusionPolicies() throws Exception {
Gson gson = new GsonBuilder()
.setExclusionStrategies(new UserDefinedExclusionStrategy(String.class))
.create();
String json = gson.toJson(new TestTypes.StringWrapper("someValue"));
assertEquals("{}", json);
}
private static class UserDefinedExclusionStrategy implements ExclusionStrategy2 {
private final Class<?> excludedThisClass;
UserDefinedExclusionStrategy(Class<?> excludedThisClass) {
this.excludedThisClass = excludedThisClass;
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
return excludedThisClass.equals(clazz);
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
return excludedThisClass.equals(f.getDeclaredClass());
}
}
}

View File

@ -16,10 +16,10 @@
package com.google.gson;
import java.lang.reflect.Field;
import junit.framework.TestCase;
import java.lang.reflect.Field;
/**
* Unit test for the {@link InnerClassExclusionStrategy} class.
*
@ -41,26 +41,22 @@ public class InnerClassExclusionStrategyTest extends TestCase {
public void testExcludeInnerClassObject() throws Exception {
Class<?> clazz = innerClass.getClass();
assertTrue(strategy.shouldSkipClass(clazz, Mode.SERIALIZE));
assertTrue(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipClass(clazz));
}
public void testExcludeInnerClassField() throws Exception {
Field f = getClass().getField("innerClass");
assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.SERIALIZE));
assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f)));
}
public void testIncludeStaticNestedClassObject() throws Exception {
Class<?> clazz = staticNestedClass.getClass();
assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz));
}
public void testIncludeStaticNestedClassField() throws Exception {
Field f = getClass().getField("staticNestedClass");
assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.SERIALIZE));
assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f)));
}
class InnerClass {

View File

@ -1,49 +0,0 @@
/*
* 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;
/**
* This is a configurable {@link ExclusionStrategy2} that can be used for
* unit testing.
*
* @author Joel Leitch
*/
public class MockExclusionStrategy2 implements ExclusionStrategy2 {
private final MockExclusionStrategy strategy;
private final Mode mode;
public MockExclusionStrategy2(boolean skipClass, boolean skipField, Mode mode) {
this.strategy = new MockExclusionStrategy(skipClass, skipField);
this.mode = mode;
}
public boolean shouldSkipField(FieldAttributes f, Mode mode) {
if (this.mode == null || this.mode == mode) {
return strategy.shouldSkipField(f);
} else {
return false;
}
}
public boolean shouldSkipClass(Class<?> clazz, Mode mode) {
if (this.mode == null || this.mode == mode) {
return strategy.shouldSkipClass(clazz);
} else {
return false;
}
}
}

View File

@ -33,16 +33,11 @@ public class NullExclusionStrategyTest extends TestCase {
}
public void testNeverSkipsClass() throws Exception {
assertFalse(strategy.shouldSkipClass(String.class, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipClass(String.class, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipClass(String.class));
}
public void testNeverSkipsField() throws Exception {
assertFalse(strategy.shouldSkipField(
new FieldAttributes(String.class, String.class.getFields()[0]),
Mode.SERIALIZE));
assertFalse(strategy.shouldSkipField(
new FieldAttributes(String.class, String.class.getFields()[0]),
Mode.DESERIALIZE));
new FieldAttributes(String.class, String.class.getFields()[0])));
}
}

View File

@ -41,39 +41,30 @@ public class VersionExclusionStrategyTest extends TestCase {
Class<MockObject> clazz = MockObject.class;
Field f = clazz.getField("someField");
VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION);
assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz));
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipField(fieldAttributes));
}
public void testClassAndFieldAreBehindInVersion() throws Exception {
Class<MockObject> clazz = MockObject.class;
Field f = clazz.getField("someField");
VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION + 1);
assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipClass(clazz));
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE));
assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE));
assertFalse(strategy.shouldSkipField(fieldAttributes));
}
public void testClassAndFieldAreAheadInVersion() throws Exception {
Class<MockObject> clazz = MockObject.class;
Field f = clazz.getField("someField");
VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION - 1);
assertTrue(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipClass(clazz, Mode.SERIALIZE));
assertTrue(strategy.shouldSkipClass(clazz));
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
assertTrue(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE));
assertTrue(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE));
assertTrue(strategy.shouldSkipField(fieldAttributes));
}
@Since(VERSION)

View File

@ -17,14 +17,11 @@
package com.google.gson.functional;
import com.google.gson.ExclusionStrategy;
import com.google.gson.ExclusionStrategy2;
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 com.google.gson.MockExclusionStrategy;
import com.google.gson.MockExclusionStrategy2;
import com.google.gson.Mode;
import junit.framework.TestCase;
@ -43,41 +40,23 @@ import java.lang.annotation.Target;
*/
public class ExclusionStrategyFunctionalTest extends TestCase {
private SampleObjectForTest src;
private Gson gson;
@Override
protected void setUp() throws Exception {
super.setUp();
gson = new GsonBuilder()
.setExclusionStrategies(new MyExclusionStrategy(String.class))
.serializeNulls()
.create();
src = new SampleObjectForTest();
}
public void testExclusionStrategySerialization() throws Exception {
Gson gson = createGson(new MyExclusionStrategy(String.class));
Gson gson = createGson(new MyExclusionStrategy(String.class), null);
String json = gson.toJson(src);
assertFalse(json.contains("\"stringField\""));
assertFalse(json.contains("\"annotatedField\""));
assertTrue(json.contains("\"longField\""));
}
public void testExclusionStrategy2Serialization() throws Exception {
Gson gson = createGson(new MockExclusionStrategy2(false, true, Mode.DESERIALIZE));
String json = gson.toJson(src);
assertTrue(json.contains("\"stringField\""));
assertTrue(json.contains("\"annotatedField\""));
assertTrue(json.contains("\"longField\""));
gson = createGson(new MockExclusionStrategy2(false, true, Mode.SERIALIZE));
json = gson.toJson(src);
assertFalse(json.contains("\"stringField\""));
assertFalse(json.contains("\"annotatedField\""));
assertFalse(json.contains("\"longField\""));
}
public void testExclusionStrategyDeserialization() throws Exception {
Gson gson = createGson(new MyExclusionStrategy(String.class), null);
JsonObject json = new JsonObject();
json.add("annotatedField", new JsonPrimitive(src.annotatedField + 5));
json.add("stringField", new JsonPrimitive(src.stringField + "blah,blah"));
@ -90,17 +69,34 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
assertEquals(src.annotatedField, target.annotatedField);
assertEquals(src.stringField, target.stringField);
}
private static Gson createGson(ExclusionStrategy exclusionStrategy) {
return new GsonBuilder()
.setExclusionStrategies(exclusionStrategy)
.serializeNulls()
.create();
}
private static Gson createGson(ExclusionStrategy2 exclusionStrategy) {
return new GsonBuilder()
.setExclusionStrategies(exclusionStrategy)
public void testExclusionStrategyWithMode() throws Exception {
SampleObjectForTest testObj = new SampleObjectForTest(
src.annotatedField + 5, src.stringField + "blah,blah",
src.longField + 655L);
Gson gson = createGson(new MyExclusionStrategy(String.class), Mode.DESERIALIZE);
JsonObject json = gson.toJsonTree(testObj).getAsJsonObject();
assertEquals(testObj.annotatedField, json.get("annotatedField").getAsInt());
assertEquals(testObj.stringField, json.get("stringField").getAsString());
assertEquals(testObj.longField, json.get("longField").getAsLong());
SampleObjectForTest target = gson.fromJson(json, SampleObjectForTest.class);
assertEquals(testObj.longField, target.longField);
// assert excluded fields are set to the defaults
assertEquals(src.annotatedField, target.annotatedField);
assertEquals(src.stringField, target.stringField);
}
private static Gson createGson(ExclusionStrategy exclusionStrategy, Mode mode) {
GsonBuilder gsonBuilder = new GsonBuilder();
if (mode == null) {
gsonBuilder.setExclusionStrategies(exclusionStrategy);
} else {
gsonBuilder.setExclusionStrategies(mode, exclusionStrategy);
}
return gsonBuilder
.serializeNulls()
.create();
}
@ -117,13 +113,15 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
private final int annotatedField;
private final String stringField;
private final long longField;
private final Class<?> clazzField;
public SampleObjectForTest() {
annotatedField = 5;
stringField = "someDefaultValue";
longField = 1234;
clazzField = String.class;
this(5, "someDefaultValue", 12345L);
}
public SampleObjectForTest(int annotatedField, String stringField, long longField) {
this.annotatedField = annotatedField;
this.stringField = stringField;
this.longField = longField;
}
}