From b883f8f4aaa7ae906b4298cc43223060495fc6ff Mon Sep 17 00:00:00 2001 From: Joel Leitch Date: Sat, 22 Jan 2011 22:15:06 +0000 Subject: [PATCH] Add new "Mode" enum and carry mode through Gson so exclusion strategies know whether it is currently serializing or deserializing. Deprecate old ExclusionStrategy code since this new approach is more powerful. --- ...onymousAndLocalClassExclusionStrategy.java | 7 +- .../gson/DisjunctionExclusionStrategy.java | 20 +-- .../com/google/gson/ExclusionStrategy.java | 2 + .../com/google/gson/ExclusionStrategy2.java | 125 ++++++++++++++++++ .../gson/ExclusionStrategy2Adapter.java | 39 ++++++ ...=> ExposeAnnotationExclusionStrategy.java} | 19 ++- gson/src/main/java/com/google/gson/Gson.java | 36 ++--- .../java/com/google/gson/GsonBuilder.java | 63 +++++---- .../gson/InnerClassExclusionStrategy.java | 6 +- .../gson/JsonDeserializationVisitor.java | 4 + .../google/gson/JsonSerializationVisitor.java | 4 + ...zationExclusionStrategy.java => Mode.java} | 27 ++-- .../gson/ModifierBasedExclusionStrategy.java | 6 +- .../google/gson/NullExclusionStrategy.java | 9 +- .../java/com/google/gson/ObjectNavigator.java | 17 ++- .../google/gson/ObjectNavigatorFactory.java | 6 +- .../gson/SyntheticFieldExclusionStrategy.java | 6 +- .../google/gson/VersionExclusionStrategy.java | 6 +- .../DisjunctionExclusionStrategyTest.java | 21 +-- .../gson/ExclusionStrategy2AdapterTest.java | 47 +++++++ ...nDeserializationExclusionStrategyTest.java | 76 ----------- ...ExposeAnnotationExclusionStrategyTest.java | 95 +++++++++++++ ...ionSerializationExclusionStrategyTest.java | 76 ----------- .../FunctionWithInternalDependenciesTest.java | 12 +- .../gson/InnerClassExclusionStrategyTest.java | 12 +- .../google/gson/MockExclusionStrategy.java | 1 - .../google/gson/MockExclusionStrategy2.java | 49 +++++++ .../gson/NullExclusionStrategyTest.java | 9 +- .../gson/VersionExclusionStrategyTest.java | 24 +++- .../functional/DefaultTypeAdaptersTest.java | 6 +- .../ExclusionStrategyFunctionalTest.java | 35 ++++- 31 files changed, 565 insertions(+), 300 deletions(-) create mode 100644 gson/src/main/java/com/google/gson/ExclusionStrategy2.java create mode 100644 gson/src/main/java/com/google/gson/ExclusionStrategy2Adapter.java rename gson/src/main/java/com/google/gson/{ExposeAnnotationSerializationExclusionStrategy.java => ExposeAnnotationExclusionStrategy.java} (67%) rename gson/src/main/java/com/google/gson/{ExposeAnnotationDeserializationExclusionStrategy.java => Mode.java} (53%) create mode 100644 gson/src/test/java/com/google/gson/ExclusionStrategy2AdapterTest.java delete mode 100644 gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java create mode 100644 gson/src/test/java/com/google/gson/ExposeAnnotationExclusionStrategyTest.java delete mode 100644 gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java create mode 100644 gson/src/test/java/com/google/gson/MockExclusionStrategy2.java diff --git a/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java b/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java index 7d48cb0e..28ae1448 100644 --- a/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java @@ -16,19 +16,18 @@ package com.google.gson; - /** * Strategy for excluding anonymous and local classes. * * @author Joel Leitch */ -final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy { +final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy2 { - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return isAnonymousOrLocal(f.getDeclaredClass()); } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return isAnonymousOrLocal(clazz); } diff --git a/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java b/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java index c7974b1a..a2ffb70f 100644 --- a/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java @@ -19,31 +19,31 @@ package com.google.gson; import java.util.Collection; /** - * A wrapper class used to collect numerous {@link ExclusionStrategy} objects + * A wrapper class used to collect numerous {@link ExclusionStrategy2} objects * and perform a short-circuited OR operation. * * @author Joel Leitch */ -final class DisjunctionExclusionStrategy implements ExclusionStrategy { - private final Collection strategies; +final class DisjunctionExclusionStrategy implements ExclusionStrategy2 { + private final Collection strategies; - public DisjunctionExclusionStrategy(Collection strategies) { + public DisjunctionExclusionStrategy(Collection strategies) { Preconditions.checkNotNull(strategies); this.strategies = strategies; } - public boolean shouldSkipField(FieldAttributes f) { - for (ExclusionStrategy strategy : strategies) { - if (strategy.shouldSkipField(f)) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { + for (ExclusionStrategy2 strategy : strategies) { + if (strategy.shouldSkipField(f, mode)) { return true; } } return false; } - public boolean shouldSkipClass(Class clazz) { - for (ExclusionStrategy strategy : strategies) { - if (strategy.shouldSkipClass(clazz)) { + public boolean shouldSkipClass(Class clazz, Mode mode) { + for (ExclusionStrategy2 strategy : strategies) { + if (strategy.shouldSkipClass(clazz, mode)) { return true; } } diff --git a/gson/src/main/java/com/google/gson/ExclusionStrategy.java b/gson/src/main/java/com/google/gson/ExclusionStrategy.java index 702d7e96..a83c5da6 100644 --- a/gson/src/main/java/com/google/gson/ExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ExclusionStrategy.java @@ -78,7 +78,9 @@ package com.google.gson; * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...) * * @since 1.4 + * @deprecated use the more powerful {@link ExclusionStrategy2} instead. */ +@Deprecated public interface ExclusionStrategy { /** diff --git a/gson/src/main/java/com/google/gson/ExclusionStrategy2.java b/gson/src/main/java/com/google/gson/ExclusionStrategy2.java new file mode 100644 index 00000000..cd67e9bd --- /dev/null +++ b/gson/src/main/java/com/google/gson/ExclusionStrategy2.java @@ -0,0 +1,125 @@ +/* + * 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. + * + *

The following are a few examples that shows how you can use this exclusion mechanism. + * + *

Exclude fields and objects based on a particular class type for both serialization + * and deserialization: + *

+ * public class SpecificClassExclusionStrategy implements ExclusionStrategy2 {
+ *   private final Class<?> excludedThisClass;
+ *
+ *   public SpecificClassExclusionStrategy(Class<?> excludedThisClass) {
+ *     this.excludedThisClass = excludedThisClass;
+ *   }
+ *
+ *   public boolean shouldSkipClass(Class<?> clazz, Context context) {
+ *     return excludedThisClass.equals(clazz);
+ *   }
+ *
+ *   public boolean shouldSkipField(FieldAttributes f, Context context) {
+ *     return excludedThisClass.equals(f.getDeclaredClass());
+ *   }
+ * }
+ * 
+ * + *

Excludes fields and objects based on a particular annotation for both serialization + * and deserialization: + *

+ * public @interface FooAnnotation {
+ *   // some implementation here
+ * }
+ *
+ * // Excludes any field (or class) that is tagged with an "@FooAnnotation"
+ * public class FooAnnotationExclusionStrategy implements ExclusionStrategy2 {
+ *   public boolean shouldSkipClass(Class<?> clazz, Context context) {
+ *     return clazz.getAnnotation(FooAnnotation.class) != null;
+ *   }
+ *
+ *   public boolean shouldSkipField(FieldAttributes f, Context context) {
+ *     return f.getAnnotation(FooAnnotation.class) != null;
+ *   }
+ * }
+ * 
+ * + *

Exclude fields and objects based on a particular class type for serialization + * only: + *

+ * public class SpecificClassExclusionStrategy implements ExclusionStrategy2 {
+ *   private final Class<?> excludedThisClass;
+ *
+ *   public SpecificClassExclusionStrategy(Class<?> excludedThisClass) {
+ *     this.excludedThisClass = excludedThisClass;
+ *   }
+ *
+ *   public boolean shouldSkipClass(Class<?> 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;
+ *     }
+ *   }
+ * }
+ * 
+ * + *

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: + *

+ * ExclusionStrategy2 excludeStrings = new UserDefinedExclusionStrategy(String.class);
+ * Gson gson = new GsonBuilder()
+ *     .setExclusionStrategies(excludeStrings)
+ *     .create();
+ * 
+ * + * @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); +} diff --git a/gson/src/main/java/com/google/gson/ExclusionStrategy2Adapter.java b/gson/src/main/java/com/google/gson/ExclusionStrategy2Adapter.java new file mode 100644 index 00000000..da24f0fb --- /dev/null +++ b/gson/src/main/java/com/google/gson/ExclusionStrategy2Adapter.java @@ -0,0 +1,39 @@ +/* + * 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; + +/** + * Adapts the old {@link ExclusionStrategy} into the newer {@link ExclusionStrategy2} type. + * + * @author Joel Leitch + */ +class ExclusionStrategy2Adapter implements ExclusionStrategy2 { + private final ExclusionStrategy strategy; + + public ExclusionStrategy2Adapter(ExclusionStrategy strategy) { + Preconditions.checkNotNull(strategy); + this.strategy = strategy; + } + + public boolean shouldSkipClass(Class clazz, Mode mode) { + return strategy.shouldSkipClass(clazz); + } + + public boolean shouldSkipField(FieldAttributes f, Mode mode) { + return strategy.shouldSkipField(f); + } +} diff --git a/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java b/gson/src/main/java/com/google/gson/ExposeAnnotationExclusionStrategy.java similarity index 67% rename from gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java rename to gson/src/main/java/com/google/gson/ExposeAnnotationExclusionStrategy.java index e248d702..9d0ece5a 100644 --- a/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ExposeAnnotationExclusionStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Google Inc. + * 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. @@ -21,20 +21,25 @@ import com.google.gson.annotations.Expose; /** * Excludes fields that do not have the {@link Expose} annotation * - * @author Inderjeet Singh * @author Joel Leitch */ -final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy { - - public boolean shouldSkipClass(Class clazz) { +public class ExposeAnnotationExclusionStrategy implements ExclusionStrategy2 { + public boolean shouldSkipClass(Class clazz, Mode mode) { return false; } - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { Expose annotation = f.getAnnotation(Expose.class); if (annotation == null) { return true; } - return !annotation.serialize(); + + if (mode == Mode.SERIALIZE) { + return !annotation.serialize(); + } else if (mode == Mode.DESERIALIZE) { + return !annotation.deserialize(); + } + + return false; } } diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index c6177659..84ec2d9e 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -92,15 +92,11 @@ public final class Gson { static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY = new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy()); - private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = - createExclusionStrategy(VersionConstants.IGNORE_VERSIONS); + private static final ExclusionStrategy2 DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy(); private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; - private final ExclusionStrategy serializationStrategy; - - private final ExclusionStrategy deserializationStrategy; - + private final ExclusionStrategy2 exclusionStrategy; private final FieldNamingStrategy2 fieldNamingPolicy; private final MappedObjectConstructor objectConstructor; @@ -150,19 +146,18 @@ public final class Gson { * */ public Gson() { - this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, + this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), false, DefaultTypeAdapters.getAllDefaultSerializers(), DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false); } - Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy, - FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor, - boolean serializeNulls, ParameterizedTypeHandlerMap> serializers, - ParameterizedTypeHandlerMap> deserializers, - boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) { - this.serializationStrategy = serializationStrategy; - this.deserializationStrategy = deserializationStrategy; + Gson(ExclusionStrategy2 exclusionStrategy, FieldNamingStrategy2 fieldNamingPolicy, + MappedObjectConstructor objectConstructor, boolean serializeNulls, + ParameterizedTypeHandlerMap> serializers, + ParameterizedTypeHandlerMap> deserializers, + boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) { + this.exclusionStrategy = exclusionStrategy; this.fieldNamingPolicy = fieldNamingPolicy; this.objectConstructor = objectConstructor; this.serializeNulls = serializeNulls; @@ -173,18 +168,15 @@ public final class Gson { this.prettyPrinting = prettyPrinting; } - private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) { + private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy2 strategy) { return new ObjectNavigatorFactory(strategy, fieldNamingPolicy); } - private static ExclusionStrategy createExclusionStrategy(double version) { - List strategies = new LinkedList(); + private static ExclusionStrategy2 createExclusionStrategy() { + List strategies = new LinkedList(); strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY); strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY); strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY); - if (version != VersionConstants.IGNORE_VERSIONS) { - strategies.add(new VersionExclusionStrategy(version)); - } return new DisjunctionExclusionStrategy(strategies); } @@ -229,7 +221,7 @@ public final class Gson { return JsonNull.createJsonNull(); } JsonSerializationContextDefault context = new JsonSerializationContextDefault( - createDefaultObjectNavigatorFactory(serializationStrategy), serializeNulls, serializers); + createDefaultObjectNavigatorFactory(exclusionStrategy), serializeNulls, serializers); return context.serialize(src, typeOfSrc, true); } @@ -563,7 +555,7 @@ public final class Gson { return null; } JsonDeserializationContext context = new JsonDeserializationContextDefault( - createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers, + createDefaultObjectNavigatorFactory(exclusionStrategy), deserializers, objectConstructor); T target = (T) context.deserialize(json, typeOfT); return target; diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index 17150314..452c26e9 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -54,15 +54,11 @@ import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter; public final class GsonBuilder { private static final InnerClassExclusionStrategy innerClassExclusionStrategy = new InnerClassExclusionStrategy(); - private static final ExposeAnnotationSerializationExclusionStrategy - exposeAnnotationSerializationExclusionStrategy = - new ExposeAnnotationSerializationExclusionStrategy(); - private static final ExposeAnnotationDeserializationExclusionStrategy - exposeAnnotationDeserializationExclusionStrategy = - new ExposeAnnotationDeserializationExclusionStrategy(); + private static final ExposeAnnotationExclusionStrategy exposeAnnotationExclusionStrategy = + new ExposeAnnotationExclusionStrategy(); - private final Collection exclusionStrategies = - new HashSet(); + private final Collection exclusionStrategies = + new HashSet(); private double ignoreVersionsAfter; private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy; @@ -247,9 +243,30 @@ 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)); + } + return this; + } + + /** + * Configures Gson to apply a set of exclusion strategies during both serialization and + * 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. + * + * @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.7 + */ + public GsonBuilder setExclusionStrategies(ExclusionStrategy2... strategies) { + for (ExclusionStrategy2 strategy : strategies) { exclusionStrategies.add(strategy); } return this; @@ -497,30 +514,20 @@ public final class GsonBuilder { * @return an instance of Gson configured with the options currently set in this builder */ public Gson create() { - List serializationStrategies = - new LinkedList(exclusionStrategies); - List deserializationStrategies = - new LinkedList(exclusionStrategies); - - serializationStrategies.add(modifierBasedExclusionStrategy); - deserializationStrategies.add(modifierBasedExclusionStrategy); + List strategies = + new LinkedList(exclusionStrategies); + strategies.add(modifierBasedExclusionStrategy); if (!serializeInnerClasses) { - serializationStrategies.add(innerClassExclusionStrategy); - deserializationStrategies.add(innerClassExclusionStrategy); + strategies.add(innerClassExclusionStrategy); } if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) { - serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); - deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); + strategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); } if (excludeFieldsWithoutExposeAnnotation) { - serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy); - deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy); + strategies.add(exposeAnnotationExclusionStrategy); } - ExclusionStrategy serializationExclusionStrategy = - new DisjunctionExclusionStrategy(serializationStrategies); - ExclusionStrategy deserializationExclusionStrategy = - new DisjunctionExclusionStrategy(deserializationStrategies); + ExclusionStrategy2 exclusionStrategy = new DisjunctionExclusionStrategy(strategies); ParameterizedTypeHandlerMap> customSerializers = DefaultTypeAdapters.DEFAULT_HIERARCHY_SERIALIZERS.copyOf(); @@ -546,9 +553,9 @@ public final class GsonBuilder { MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators); - Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy, - fieldNamingPolicy, objConstructor, serializeNulls, customSerializers, - customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting); + Gson gson = new Gson(exclusionStrategy, fieldNamingPolicy, objConstructor, serializeNulls, + customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars, + prettyPrinting); return gson; } diff --git a/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java b/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java index e125bfae..6dda7e4f 100644 --- a/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java @@ -23,13 +23,13 @@ import java.lang.reflect.Modifier; * * @author Joel Leitch */ -class InnerClassExclusionStrategy implements ExclusionStrategy { +class InnerClassExclusionStrategy implements ExclusionStrategy2 { - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return isInnerClass(f.getDeclaredClass()); } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return isInnerClass(clazz); } diff --git a/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java b/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java index edae425f..02644e57 100644 --- a/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java @@ -58,6 +58,10 @@ abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor } return target; } + + public Mode getMode() { + return Mode.DESERIALIZE; + } protected abstract T constructTarget(); diff --git a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java index 0649a5a7..6d0e3917 100644 --- a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java @@ -47,6 +47,10 @@ 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) { diff --git a/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java b/gson/src/main/java/com/google/gson/Mode.java similarity index 53% rename from gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java rename to gson/src/main/java/com/google/gson/Mode.java index c087e81f..47fa4cfa 100644 --- a/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/Mode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. + * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,27 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.google.gson; -import com.google.gson.annotations.Expose; - /** - * Excludes fields that do not have the {@link Expose} annotation + * Defines the current context of Gson so that common code for serializing and deserializing can + * distinguish between the two modes. * - * @author Inderjeet Singh * @author Joel Leitch + * + * @since 1.7 */ -final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy { - - public boolean shouldSkipClass(Class clazz) { - return false; - } - - public boolean shouldSkipField(FieldAttributes f) { - Expose annotation = f.getAnnotation(Expose.class); - if (annotation == null) { - return true; - } - return !annotation.deserialize(); - } +public enum Mode { + SERIALIZE, + DESERIALIZE; } diff --git a/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java b/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java index fdf8e5ba..fa8bffc9 100644 --- a/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java @@ -26,7 +26,7 @@ import java.util.HashSet; * @author Inderjeet Singh * @author Joel Leitch */ -final class ModifierBasedExclusionStrategy implements ExclusionStrategy { +final class ModifierBasedExclusionStrategy implements ExclusionStrategy2 { private final Collection modifiers; public ModifierBasedExclusionStrategy(int... modifiers) { @@ -38,7 +38,7 @@ final class ModifierBasedExclusionStrategy implements ExclusionStrategy { } } - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { for (int modifier : modifiers) { if (f.hasModifier(modifier)) { return true; @@ -47,7 +47,7 @@ final class ModifierBasedExclusionStrategy implements ExclusionStrategy { return false; } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return false; } } diff --git a/gson/src/main/java/com/google/gson/NullExclusionStrategy.java b/gson/src/main/java/com/google/gson/NullExclusionStrategy.java index c7a1bafa..5f9a806a 100644 --- a/gson/src/main/java/com/google/gson/NullExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/NullExclusionStrategy.java @@ -16,22 +16,21 @@ package com.google.gson; - /** - * This acts as a "Null Object" pattern for the {@link ExclusionStrategy}. + * This acts as a "Null Object" pattern for the {@link ExclusionStrategy2}. * Passing an instance of this class into the {@link ObjectNavigator} will * make the {@link ObjectNavigator} parse/visit every field of the object * being navigated. * * @author Joel Leitch */ -final class NullExclusionStrategy implements ExclusionStrategy { +final class NullExclusionStrategy implements ExclusionStrategy2 { - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return false; } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return false; } } diff --git a/gson/src/main/java/com/google/gson/ObjectNavigator.java b/gson/src/main/java/com/google/gson/ObjectNavigator.java index 0738c709..2eefd57f 100644 --- a/gson/src/main/java/com/google/gson/ObjectNavigator.java +++ b/gson/src/main/java/com/google/gson/ObjectNavigator.java @@ -69,15 +69,17 @@ final class ObjectNavigator { public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent); + void visitPrimitive(Object primitive); + /** * Retrieve the current target */ Object getTarget(); - - void visitPrimitive(Object primitive); + + Mode getMode(); } - private final ExclusionStrategy exclusionStrategy; + private final ExclusionStrategy2 exclusionStrategy; private final ObjectTypePair objTypePair; /** @@ -87,7 +89,7 @@ final class ObjectNavigator { * the concrete strategy object to be used to filter out fields of an * object. */ - ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) { + ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy2 exclusionStrategy) { Preconditions.checkNotNull(exclusionStrategy); this.objTypePair = objTypePair; @@ -99,7 +101,7 @@ final class ObjectNavigator { * does not get visited. */ public void accept(Visitor visitor) { - if (exclusionStrategy.shouldSkipClass(Types.getRawType(objTypePair.type))) { + if (exclusionStrategy.shouldSkipClass(Types.getRawType(objTypePair.type), visitor.getMode())) { return; } boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair); @@ -143,12 +145,13 @@ 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) - || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) { + if (exclusionStrategy.shouldSkipField(fieldAttributes, mode) + || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass(), mode)) { continue; // skip } Type declaredTypeOfField = getTypeInfoForField(f, objTypePair.type); diff --git a/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java b/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java index 3f90cea3..b2e501e1 100644 --- a/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java +++ b/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java @@ -18,13 +18,13 @@ package com.google.gson; /** * A factory class used to simplify {@link ObjectNavigator} creation. - * This object holds on to a reference of the {@link ExclusionStrategy} + * This object holds on to a reference of the {@link ExclusionStrategy2} * that you'd like to use with the {@link ObjectNavigator}. * * @author Joel Leitch */ final class ObjectNavigatorFactory { - private final ExclusionStrategy strategy; + private final ExclusionStrategy2 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(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) { + public ObjectNavigatorFactory(ExclusionStrategy2 strategy, FieldNamingStrategy2 fieldNamingPolicy) { Preconditions.checkNotNull(fieldNamingPolicy); this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy); this.fieldNamingPolicy = fieldNamingPolicy; diff --git a/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java b/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java index ab90c5d0..8c575916 100644 --- a/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java @@ -26,18 +26,18 @@ package com.google.gson; * * @since 1.4 */ -class SyntheticFieldExclusionStrategy implements ExclusionStrategy { +class SyntheticFieldExclusionStrategy implements ExclusionStrategy2 { private final boolean skipSyntheticFields; SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) { this.skipSyntheticFields = skipSyntheticFields; } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return false; } - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return skipSyntheticFields && f.isSynthetic(); } diff --git a/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java b/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java index 8bd726f3..498e35f9 100644 --- a/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java @@ -25,7 +25,7 @@ import com.google.gson.annotations.Until; * * @author Joel Leitch */ -final class VersionExclusionStrategy implements ExclusionStrategy { +final class VersionExclusionStrategy implements ExclusionStrategy2 { private final double version; public VersionExclusionStrategy(double version) { @@ -33,11 +33,11 @@ final class VersionExclusionStrategy implements ExclusionStrategy { this.version = version; } - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class)); } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class)); } diff --git a/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java index 34fcccb8..47d9cd76 100644 --- a/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java @@ -28,35 +28,38 @@ import junit.framework.TestCase; */ public class DisjunctionExclusionStrategyTest extends TestCase { - private static final ExclusionStrategy FALSE_STRATEGY = new MockExclusionStrategy(false, false); - private static final ExclusionStrategy TRUE_STRATEGY = new MockExclusionStrategy(true, true); + 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 Class CLAZZ = String.class; private static final FieldAttributes FIELD = new FieldAttributes(CLAZZ, CLAZZ.getFields()[0]); public void testBadInstantiation() throws Exception { try { - List constructorParam = null; + List constructorParam = null; new DisjunctionExclusionStrategy(constructorParam); fail("Should throw an exception"); } catch (IllegalArgumentException expected) { } } public void testSkipFieldsWithMixedTrueAndFalse() throws Exception { - List strategies = new LinkedList(); + List strategies = new LinkedList(); strategies.add(FALSE_STRATEGY); strategies.add(TRUE_STRATEGY); DisjunctionExclusionStrategy strategy = new DisjunctionExclusionStrategy(strategies); - assertTrue(strategy.shouldSkipClass(CLAZZ)); - assertTrue(strategy.shouldSkipField(FIELD)); + assertTrue(strategy.shouldSkipClass(CLAZZ, Mode.SERIALIZE)); + assertTrue(strategy.shouldSkipField(FIELD, Mode.SERIALIZE)); } public void testSkipFieldsWithFalseOnly() throws Exception { - List strategies = new LinkedList(); + List strategies = new LinkedList(); strategies.add(FALSE_STRATEGY); DisjunctionExclusionStrategy strategy = new DisjunctionExclusionStrategy(strategies); - assertFalse(strategy.shouldSkipClass(CLAZZ)); - assertFalse(strategy.shouldSkipField(FIELD)); + assertFalse(strategy.shouldSkipClass(CLAZZ, Mode.SERIALIZE)); + assertFalse(strategy.shouldSkipField(FIELD, Mode.SERIALIZE)); } } diff --git a/gson/src/test/java/com/google/gson/ExclusionStrategy2AdapterTest.java b/gson/src/test/java/com/google/gson/ExclusionStrategy2AdapterTest.java new file mode 100644 index 00000000..173dcbd4 --- /dev/null +++ b/gson/src/test/java/com/google/gson/ExclusionStrategy2AdapterTest.java @@ -0,0 +1,47 @@ +/* + * 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)); + } +} diff --git a/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java deleted file mode 100644 index 8fcdb577..00000000 --- a/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java +++ /dev/null @@ -1,76 +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; - -import java.lang.reflect.Field; - -import junit.framework.TestCase; - -import com.google.gson.annotations.Expose; - -/** - * Unit tests for the {@link ExposeAnnotationDeserializationExclusionStrategy} class. - * - * @author Joel Leitch - */ -public class ExposeAnnotationDeserializationExclusionStrategyTest extends TestCase { - private ExposeAnnotationDeserializationExclusionStrategy strategy; - - @Override - protected void setUp() throws Exception { - super.setUp(); - strategy = new ExposeAnnotationDeserializationExclusionStrategy(); - } - - public void testNeverSkipClasses() throws Exception { - assertFalse(strategy.shouldSkipClass(MockObject.class)); - } - - public void testSkipNonAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("hiddenField"); - assertTrue(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testSkipExplicitlySkippedFields() throws Exception { - Field f = MockObject.class.getField("explicitlyHiddenField"); - assertTrue(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testNeverSkipExposedAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("exposedField"); - assertFalse(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("explicitlyExposedField"); - assertFalse(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - @SuppressWarnings("unused") - private static class MockObject { - @Expose - public final int exposedField = 0; - - @Expose(deserialize=true) - public final int explicitlyExposedField = 0; - - @Expose(deserialize=false) - public final int explicitlyHiddenField = 0; - - public final int hiddenField = 0; - } -} diff --git a/gson/src/test/java/com/google/gson/ExposeAnnotationExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/ExposeAnnotationExclusionStrategyTest.java new file mode 100644 index 00000000..db040a4b --- /dev/null +++ b/gson/src/test/java/com/google/gson/ExposeAnnotationExclusionStrategyTest.java @@ -0,0 +1,95 @@ +/* + * 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 com.google.gson.annotations.Expose; + +import junit.framework.TestCase; + +/** + * Unit tests for the {@link ExposeAnnotationExclusionStrategy} class. + * + * @author Joel Leitch + */ +public class ExposeAnnotationExclusionStrategyTest extends TestCase { + private ExposeAnnotationExclusionStrategy strategy; + + @Override + protected void setUp() throws Exception { + super.setUp(); + strategy = new ExposeAnnotationExclusionStrategy(); + } + + public void testNeverSkipClasses() throws Exception { + assertFalse(strategy.shouldSkipClass(MockObject.class, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipClass(MockObject.class, Mode.SERIALIZE)); + } + + public void testSkipNonAnnotatedFields() throws Exception { + FieldAttributes f = createFieldAttributes("hiddenField"); + assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE)); + assertTrue(strategy.shouldSkipField(f, Mode.SERIALIZE)); + } + + public void testSkipExplicitlySkippedFields() throws Exception { + FieldAttributes f = createFieldAttributes("explicitlyHiddenField"); + assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE)); + assertTrue(strategy.shouldSkipField(f, Mode.SERIALIZE)); + } + + public void testNeverSkipExposedAnnotatedFields() throws Exception { + FieldAttributes f = createFieldAttributes("exposedField"); + assertFalse(strategy.shouldSkipField(f, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE)); + } + + public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { + FieldAttributes f = createFieldAttributes("explicitlyExposedField"); + assertFalse(strategy.shouldSkipField(f, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE)); + } + + public void testDifferentSerializeAndDeserializeField() throws Exception { + FieldAttributes f = createFieldAttributes("explicitlyDifferentModeField"); + assertTrue(strategy.shouldSkipField(f, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipField(f, Mode.SERIALIZE)); + } + + private static FieldAttributes createFieldAttributes(String fieldName) throws Exception { + Field f = MockObject.class.getField(fieldName); + return new FieldAttributes(MockObject.class, f); + } + + @SuppressWarnings("unused") + private static class MockObject { + @Expose + public final int exposedField = 0; + + @Expose(serialize=true, deserialize=true) + public final int explicitlyExposedField = 0; + + @Expose(serialize=false, deserialize=false) + public final int explicitlyHiddenField = 0; + + @Expose(serialize=true, deserialize=false) + public final int explicitlyDifferentModeField = 0; + + public final int hiddenField = 0; + } +} diff --git a/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java deleted file mode 100644 index 08ead177..00000000 --- a/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java +++ /dev/null @@ -1,76 +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; - -import java.lang.reflect.Field; - -import junit.framework.TestCase; - -import com.google.gson.annotations.Expose; - -/** - * Unit tests for the {@link ExposeAnnotationSerializationExclusionStrategy} class. - * - * @author Joel Leitch - */ -public class ExposeAnnotationSerializationExclusionStrategyTest extends TestCase { - private ExposeAnnotationSerializationExclusionStrategy strategy; - - @Override - protected void setUp() throws Exception { - super.setUp(); - strategy = new ExposeAnnotationSerializationExclusionStrategy(); - } - - public void testNeverSkipClasses() throws Exception { - assertFalse(strategy.shouldSkipClass(MockObject.class)); - } - - public void testSkipNonAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("hiddenField"); - assertTrue(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testSkipExplicitlySkippedFields() throws Exception { - Field f = MockObject.class.getField("explicitlyHiddenField"); - assertTrue(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testNeverSkipExposedAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("exposedField"); - assertFalse(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { - Field f = MockObject.class.getField("explicitlyExposedField"); - assertFalse(strategy.shouldSkipField(new FieldAttributes(MockObject.class, f))); - } - - @SuppressWarnings("unused") - private static class MockObject { - @Expose - public final int exposedField = 0; - - @Expose(serialize=true) - public final int explicitlyExposedField = 0; - - @Expose(serialize=false) - public final int explicitlyHiddenField = 0; - - public final int hiddenField = 0; - } -} diff --git a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java index 736141f5..aee7f3ea 100644 --- a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java +++ b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java @@ -35,11 +35,11 @@ import com.google.gson.common.TestTypes.ClassWithNoFields; public class FunctionWithInternalDependenciesTest extends TestCase { public void testAnonymousLocalClassesSerialization() throws Exception { - LinkedList strategies = new LinkedList(); + LinkedList strategies = new LinkedList(); strategies.add(new SyntheticFieldExclusionStrategy(true)); strategies.add(new ModifierBasedExclusionStrategy(Modifier.TRANSIENT, Modifier.STATIC)); - ExclusionStrategy exclusionStrategy = new DisjunctionExclusionStrategy(strategies); - Gson gson = new Gson(exclusionStrategy, exclusionStrategy, Gson.DEFAULT_NAMING_POLICY, + ExclusionStrategy2 exclusionStrategy = new DisjunctionExclusionStrategy(strategies); + Gson gson = new Gson(exclusionStrategy, Gson.DEFAULT_NAMING_POLICY, new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), false, DefaultTypeAdapters.getDefaultSerializers(), DefaultTypeAdapters.getDefaultDeserializers(), Gson.DEFAULT_JSON_NON_EXECUTABLE, true, @@ -60,18 +60,18 @@ public class FunctionWithInternalDependenciesTest extends TestCase { assertEquals("{}", json); } - private static class UserDefinedExclusionStrategy implements ExclusionStrategy { + private static class UserDefinedExclusionStrategy implements ExclusionStrategy2 { private final Class excludedThisClass; UserDefinedExclusionStrategy(Class excludedThisClass) { this.excludedThisClass = excludedThisClass; } - public boolean shouldSkipClass(Class clazz) { + public boolean shouldSkipClass(Class clazz, Mode mode) { return excludedThisClass.equals(clazz); } - public boolean shouldSkipField(FieldAttributes f) { + public boolean shouldSkipField(FieldAttributes f, Mode mode) { return excludedThisClass.equals(f.getDeclaredClass()); } diff --git a/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java index 4f6c4aad..3fb10d4d 100644 --- a/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java @@ -41,22 +41,26 @@ public class InnerClassExclusionStrategyTest extends TestCase { public void testExcludeInnerClassObject() throws Exception { Class clazz = innerClass.getClass(); - assertTrue(strategy.shouldSkipClass(clazz)); + assertTrue(strategy.shouldSkipClass(clazz, Mode.SERIALIZE)); + assertTrue(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE)); } public void testExcludeInnerClassField() throws Exception { Field f = getClass().getField("innerClass"); - assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f))); + assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.SERIALIZE)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.DESERIALIZE)); } public void testIncludeStaticNestedClassObject() throws Exception { Class clazz = staticNestedClass.getClass(); - assertFalse(strategy.shouldSkipClass(clazz)); + assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE)); + assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE)); } public void testIncludeStaticNestedClassField() throws Exception { Field f = getClass().getField("staticNestedClass"); - assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f))); + assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.SERIALIZE)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(getClass(), f), Mode.DESERIALIZE)); } class InnerClass { diff --git a/gson/src/test/java/com/google/gson/MockExclusionStrategy.java b/gson/src/test/java/com/google/gson/MockExclusionStrategy.java index 6b7a3bab..cc105f51 100644 --- a/gson/src/test/java/com/google/gson/MockExclusionStrategy.java +++ b/gson/src/test/java/com/google/gson/MockExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; - /** * This is a configurable {@link ExclusionStrategy} that can be used for * unit testing. diff --git a/gson/src/test/java/com/google/gson/MockExclusionStrategy2.java b/gson/src/test/java/com/google/gson/MockExclusionStrategy2.java new file mode 100644 index 00000000..28d2dc51 --- /dev/null +++ b/gson/src/test/java/com/google/gson/MockExclusionStrategy2.java @@ -0,0 +1,49 @@ +/* + * 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; + } + } +} diff --git a/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java index 7710db19..12b0b1c0 100644 --- a/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java @@ -33,11 +33,16 @@ public class NullExclusionStrategyTest extends TestCase { } public void testNeverSkipsClass() throws Exception { - assertFalse(strategy.shouldSkipClass(String.class)); + assertFalse(strategy.shouldSkipClass(String.class, Mode.SERIALIZE)); + assertFalse(strategy.shouldSkipClass(String.class, Mode.DESERIALIZE)); } public void testNeverSkipsField() throws Exception { assertFalse(strategy.shouldSkipField( - new FieldAttributes(String.class, String.class.getFields()[0]))); + new FieldAttributes(String.class, String.class.getFields()[0]), + Mode.SERIALIZE)); + assertFalse(strategy.shouldSkipField( + new FieldAttributes(String.class, String.class.getFields()[0]), + Mode.DESERIALIZE)); } } diff --git a/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java index 26263816..cdda45ab 100644 --- a/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java @@ -42,8 +42,12 @@ public class VersionExclusionStrategyTest extends TestCase { Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION); - assertFalse(strategy.shouldSkipClass(clazz)); - assertFalse(strategy.shouldSkipField(new FieldAttributes(clazz, f))); + assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE)); + + FieldAttributes fieldAttributes = new FieldAttributes(clazz, f); + assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE)); } public void testClassAndFieldAreBehindInVersion() throws Exception { @@ -51,8 +55,12 @@ public class VersionExclusionStrategyTest extends TestCase { Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION + 1); - assertFalse(strategy.shouldSkipClass(clazz)); - assertFalse(strategy.shouldSkipField(new FieldAttributes(clazz, f))); + assertFalse(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipClass(clazz, Mode.SERIALIZE)); + + FieldAttributes fieldAttributes = new FieldAttributes(clazz, f); + assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE)); + assertFalse(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE)); } public void testClassAndFieldAreAheadInVersion() throws Exception { @@ -60,8 +68,12 @@ public class VersionExclusionStrategyTest extends TestCase { Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION - 1); - assertTrue(strategy.shouldSkipClass(clazz)); - assertTrue(strategy.shouldSkipField(new FieldAttributes(clazz, f))); + assertTrue(strategy.shouldSkipClass(clazz, Mode.DESERIALIZE)); + assertTrue(strategy.shouldSkipClass(clazz, Mode.SERIALIZE)); + + FieldAttributes fieldAttributes = new FieldAttributes(clazz, f); + assertTrue(strategy.shouldSkipField(fieldAttributes, Mode.DESERIALIZE)); + assertTrue(strategy.shouldSkipField(fieldAttributes, Mode.SERIALIZE)); } @Since(VERSION) diff --git a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java index 89d8ad38..097b8684 100644 --- a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java @@ -225,9 +225,9 @@ public class DefaultTypeAdaptersTest extends TestCase { // millisecond portion. @SuppressWarnings("deprecation") private void assertEqualsDate(Date date, int year, int month, int day) { - assertEquals(year-1900, date.getYear()); - assertEquals(month, date.getMonth()); - assertEquals(day, date.getDate()); + assertEquals(year-1900, date.getYear()); + assertEquals(month, date.getMonth()); + assertEquals(day, date.getDate()); } @SuppressWarnings("deprecation") diff --git a/gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctionalTest.java b/gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctionalTest.java index db10ecfc..34f927bc 100644 --- a/gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctionalTest.java +++ b/gson/src/test/java/com/google/gson/functional/ExclusionStrategyFunctionalTest.java @@ -17,11 +17,15 @@ 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; @@ -32,7 +36,7 @@ import java.lang.annotation.Target; /** * Performs some functional tests when Gson is instantiated with some common user defined - * {@link ExclusionStrategy} objects. + * {@link ExclusionStrategy} and {@link ExclusionStrategy2} objects. * * @author Inderjeet Singh * @author Joel Leitch @@ -52,11 +56,26 @@ public class ExclusionStrategyFunctionalTest extends TestCase { } public void testExclusionStrategySerialization() throws Exception { + Gson gson = createGson(new MyExclusionStrategy(String.class)); 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 { JsonObject json = new JsonObject(); @@ -72,6 +91,20 @@ public class ExclusionStrategyFunctionalTest extends TestCase { 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) + .serializeNulls() + .create(); + } + @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) private static @interface Foo {