diff --git a/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java b/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java index 90cdea23..cb87ad37 100644 --- a/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/AnonymousAndLocalClassExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; /** * Strategy for excluding anonymous and local classes. @@ -25,8 +24,8 @@ import java.lang.reflect.Field; */ final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy { - public boolean shouldSkipField(Field f) { - return isAnonymousOrLocal(f.getType()); + public boolean shouldSkipField(FieldAttributes f) { + return isAnonymousOrLocal(f.getDeclaredClass()); } public boolean shouldSkipClass(Class clazz) { diff --git a/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java b/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java index 236c0a43..c7974b1a 100644 --- a/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/DisjunctionExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; import java.util.Collection; /** @@ -33,7 +32,7 @@ final class DisjunctionExclusionStrategy implements ExclusionStrategy { this.strategies = strategies; } - public boolean shouldSkipField(Field f) { + public boolean shouldSkipField(FieldAttributes f) { for (ExclusionStrategy strategy : strategies) { if (strategy.shouldSkipField(f)) { 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 51156463..f4183a0c 100644 --- a/gson/src/main/java/com/google/gson/ExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ExclusionStrategy.java @@ -16,31 +16,55 @@ package com.google.gson; -import java.lang.reflect.Field; - /** - * A strategy definition that is used by the {@link ObjectNavigator} to - * determine whether or not the field of the object should be ignored during - * navigation. + * A strategy pattern (see "Design Patterns" written by GoF for some literature on this pattern) + * definition that is used to decide whether or not a field or top-level class should be serialized + * (or deserialized) as part of the JSON output/input. * - * As well, for now this class is also responsible for excluding entire - * classes. This is somewhat a mixing of concerns for this object, but - * it will suffice for now. We can always break it down into two - * different strategies later. + *

The following example show an implementation of an {@code ExclusionStrategy} where a specific + * type will be excluded from the output. * + *

+ * private static class UserDefinedExclusionStrategy implements ExclusionStrategy {
+ *   private final Class<?> excludedThisClass;
+ *
+ *   UserDefinedExclusionStrategy(Class<?> excludedThisClass) {
+ *     this.excludedThisClass = excludedThisClass;
+ *   }
+ *
+ *   public boolean shouldSkipClass(Class<?> clazz) {
+ *     return excludedThisClass.equals(clazz);
+ *   }
+ *
+ *   public boolean shouldSkipField(FieldAttributes f) {
+ *     return excludedThisClass.equals(f.getDeclaredClass());
+ *   }
+ * }
+ *
+ * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
+ * Gson gson = new GsonBuilder()
+ *     .setExclusionStrategies(excludeStrings)
+ *     .create();
+ * 
+ * + * @author Inderjeet Singh * @author Joel Leitch + * + * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...) + * + * @since 1.4 */ interface ExclusionStrategy { /** * @param f the field object that is under test - * @return true if the field should be ignored otherwise false + * @return true if the field should be ignored; otherwise false */ - public boolean shouldSkipField(Field f); + public boolean shouldSkipField(FieldAttributes f); /** * @param clazz the class object that is under test - * @return true if the class should be ignored otherwise false + * @return true if the class should be ignored; otherwise false */ public boolean shouldSkipClass(Class clazz); } diff --git a/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java b/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java index b54b642d..c087e81f 100644 --- a/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java @@ -15,13 +15,11 @@ */ package com.google.gson; -import java.lang.reflect.Field; - import com.google.gson.annotations.Expose; /** * Excludes fields that do not have the {@link Expose} annotation - * + * * @author Inderjeet Singh * @author Joel Leitch */ @@ -31,7 +29,7 @@ final class ExposeAnnotationDeserializationExclusionStrategy implements Exclusio return false; } - public boolean shouldSkipField(Field f) { + public boolean shouldSkipField(FieldAttributes f) { Expose annotation = f.getAnnotation(Expose.class); if (annotation == null) { return true; diff --git a/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java b/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java index f8d68c00..e248d702 100644 --- a/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java @@ -18,11 +18,9 @@ package com.google.gson; import com.google.gson.annotations.Expose; -import java.lang.reflect.Field; - /** * Excludes fields that do not have the {@link Expose} annotation - * + * * @author Inderjeet Singh * @author Joel Leitch */ @@ -32,7 +30,7 @@ final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionS return false; } - public boolean shouldSkipField(Field f) { + public boolean shouldSkipField(FieldAttributes f) { Expose annotation = f.getAnnotation(Expose.class); if (annotation == null) { return true; diff --git a/gson/src/main/java/com/google/gson/FieldAttributes.java b/gson/src/main/java/com/google/gson/FieldAttributes.java new file mode 100644 index 00000000..3f44c7f9 --- /dev/null +++ b/gson/src/main/java/com/google/gson/FieldAttributes.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Type; + +/** + * A data object that stores attributes of a field. + * + *

This class is immutable; therefore, it can be safely shared across threads. + * + * @author Inderjeet Singh + * @author Joel Leitch + * + * @since 1.4 + */ +final class FieldAttributes { + private final Field field; + + /** + * Constructs a Field Attributes object + * @param f + */ + FieldAttributes(Field f) { + Preconditions.checkNotNull(f); + field = f; + } + + /** + * @return the name of the field + */ + public String getName() { + return field.getName(); + } + + /** + *

For example, assume the following class definition: + *

+   * public class Foo {
+   *   private String bar;
+   *   private List<String> red;
+   * }
+   *
+   * Type listParmeterizedType = new TypeToken>() {}.getType();
+   * 
+ * + *

This method would return {@code String.class} for the {@code bar} field and + * {@code listParameterizedType} for the {@code red} field. + * + * @return the specific type declared for this field + */ + public Type getDeclaredType() { + return field.getGenericType(); + } + + /** + * Returns the {@code Class} object that was declared for this field. + * + *

For example, assume the following class definition: + *

+   * public class Foo {
+   *   private String bar;
+   *   private List<String> red;
+   * }
+   * 
+ * + *

This method would return {@code String.class} for the {@code bar} field and + * {@code List.class} for the {@code red} field. + * + * @return the specific class object that was declared for the field + */ + public Class getDeclaredClass() { + return field.getType(); + } + + /** + * Return the {@link T} annotation object from this field if it exist; otherwise returns + * {@code null}. + * + * @param annotation the class of the annotation that will be retrieved + * @return the annotation instance if it is bound to the field; otherwise {@code null} + */ + public T getAnnotation(Class annotation) { + return field.getAnnotation(annotation); + } + + /** + * Returns {@code true} if the field is defined with the {@code modifier}. + * + *

This method is meant to be called as: + *

+   * boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);
+   * 
+ * + * @see java.lang.reflect.Modifier + */ + public boolean hasModifier(int modifier) { + return (field.getModifiers() & modifier) != 0; + } + + /** + * This is exposed internally only for the + * @return + */ + boolean isSynthetic() { + return field.isSynthetic(); + } +} diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 9806f34e..5cc1ebe8 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -77,20 +77,27 @@ public final class Gson { private static final String NULL_STRING = "null"; static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; - + // Default instances of plug-ins + static final AnonymousAndLocalClassExclusionStrategy DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY = + new AnonymousAndLocalClassExclusionStrategy(); + static final SyntheticFieldExclusionStrategy DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY = + new SyntheticFieldExclusionStrategy(true); static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY = - new ModifierBasedExclusionStrategy(true, new int[] { Modifier.TRANSIENT, Modifier.STATIC }); + new ModifierBasedExclusionStrategy(new int[] { Modifier.TRANSIENT, Modifier.STATIC }); static final JsonFormatter DEFAULT_JSON_FORMATTER = new JsonCompactFormatter(); static final FieldNamingStrategy DEFAULT_NAMING_POLICY = new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy()); + private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = + createExclusionStrategy(VersionConstants.IGNORE_VERSIONS); + private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; private final ExclusionStrategy serializationStrategy; private final ExclusionStrategy deserializationStrategy; - + private final FieldNamingStrategy fieldNamingPolicy; private final MappedObjectConstructor objectConstructor; @@ -121,7 +128,7 @@ public final class Gson { * {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer * to change the default representation, you can do so by registering a type adapter through * {@link GsonBuilder#registerTypeAdapter(Type, Object)}. - *
  • The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format + *
  • The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format * ignores the millisecond portion of the date during serialization. You can change * this by invoking {@link GsonBuilder#setDateFormat(int)} or * {@link GsonBuilder#setDateFormat(String)}.
  • @@ -140,25 +147,17 @@ public final class Gson { * */ public Gson() { - this(createExclusionStrategy(VersionConstants.IGNORE_VERSIONS), DEFAULT_NAMING_POLICY); + this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, + new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), + DEFAULT_JSON_FORMATTER, false, DefaultTypeAdapters.getDefaultSerializers(), + DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE); } - /** - * Constructs a Gson object with the specified version and the mode of operation while - * encountering inner class references. - */ - Gson(ExclusionStrategy strategy, FieldNamingStrategy fieldNamingPolicy) { - this(strategy, strategy, fieldNamingPolicy, - new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), - DEFAULT_JSON_FORMATTER, false, DefaultTypeAdapters.getDefaultSerializers(), - DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE); - } - - Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy, - FieldNamingStrategy fieldNamingPolicy, MappedObjectConstructor objectConstructor, - JsonFormatter formatter, boolean serializeNulls, + Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy, + FieldNamingStrategy fieldNamingPolicy, MappedObjectConstructor objectConstructor, + JsonFormatter formatter, boolean serializeNulls, ParameterizedTypeHandlerMap> serializers, - ParameterizedTypeHandlerMap> deserializers, + ParameterizedTypeHandlerMap> deserializers, boolean generateNonExecutableGson) { this.serializationStrategy = serializationStrategy; this.deserializationStrategy = deserializationStrategy; @@ -170,14 +169,15 @@ public final class Gson { this.deserializers = deserializers; this.generateNonExecutableJson = generateNonExecutableGson; } - + private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) { return new ObjectNavigatorFactory(strategy, fieldNamingPolicy); } private static ExclusionStrategy createExclusionStrategy(double version) { List strategies = new LinkedList(); - strategies.add(new AnonymousAndLocalClassExclusionStrategy()); + 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)); @@ -186,7 +186,7 @@ public final class Gson { } /** - * This method serializes the specified object into its equivalent representation as a tree of + * This method serializes the specified object into its equivalent representation as a tree of * {@link JsonElement}s. This method should be used when the specified object is not a generic * type. This method uses {@link Class#getClass()} to get the type for the specified object, but * the {@code getClass()} loses the generic type information because of the Type Erasure feature @@ -207,9 +207,9 @@ public final class Gson { /** * This method serializes the specified object, including those of generic types, into its - * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the - * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)} - * instead. + * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the + * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)} + * instead. * * @param src the object for which JSON representation is to be created * @param typeOfSrc The specific genericized type of src. You can obtain @@ -318,7 +318,7 @@ public final class Gson { /** * Converts a tree of {@link JsonElement}s into its equivalent JSON representation. - * + * * @param jsonElement root of a tree of {@link JsonElement}s * @return JSON String representation of the tree * @since 1.4 @@ -328,10 +328,10 @@ public final class Gson { toJson(jsonElement, writer); return writer.toString(); } - + /** * Writes out the equivalent JSON for a tree of {@link JsonElement}s. - * + * * @param jsonElement root of a tree of {@link JsonElement}s * @param writer Writer to which the Json representation needs to be written * @since 1.4 @@ -347,7 +347,7 @@ public final class Gson { formatter.format(jsonElement, writer, serializeNulls); } catch (IOException e) { throw new RuntimeException(e); - } + } } /** @@ -452,9 +452,9 @@ public final class Gson { * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if the any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(JsonElement, Type)}. + * invoke {@link #fromJson(JsonElement, Type)}. * @param the type of the desired object - * @param json the root of the parse tree of {@link JsonElement}s from which the object is to + * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized * @param classOfT The class of T * @return an object of type T from the json @@ -469,10 +469,10 @@ public final class Gson { /** * This method deserializes the Json read from the specified parse tree into an object of the * specified type. This method is useful if the specified object is a generic type. For - * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. + * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. * * @param the type of the desired object - * @param json the root of the parse tree of {@link JsonElement}s from which the object is to + * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized * @param typeOfT The specific genericized type of src. You can obtain this type by using the * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for @@ -490,7 +490,7 @@ public final class Gson { return null; } JsonDeserializationContext context = new JsonDeserializationContextDefault( - createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers, + createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers, objectConstructor); T target = (T) context.deserialize(json, typeOfT); return target; @@ -504,15 +504,15 @@ public final class Gson { private void writeOutNullString(Appendable writer) throws IOException { writer.append(NULL_STRING); } - - @Override + + @Override public String toString() { StringBuilder sb = new StringBuilder("{") .append("serializeNulls:").append(serializeNulls) .append(",serializers:").append(serializers) .append(",deserializers:").append(deserializers) - - // using the name instanceCreator instead of ObjectConstructor since the users of Gson are + + // using the name instanceCreator instead of ObjectConstructor since the users of Gson are // more familiar with the concept of Instance Creators. Moreover, the objectConstructor is // just a utility class around instance creators, and its toString() only displays them. .append(",instanceCreators:").append(objectConstructor) diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index fd01a16f..8760292e 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -18,7 +18,9 @@ package com.google.gson; import java.lang.reflect.Type; import java.text.DateFormat; +import java.util.Collection; import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -50,17 +52,18 @@ import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter; * @author Joel Leitch */ public final class GsonBuilder { - private static final AnonymousAndLocalClassExclusionStrategy anonAndLocalClassExclusionStrategy = - new AnonymousAndLocalClassExclusionStrategy(); private static final InnerClassExclusionStrategy innerClassExclusionStrategy = new InnerClassExclusionStrategy(); - private static final ExposeAnnotationSerializationExclusionStrategy + private static final ExposeAnnotationSerializationExclusionStrategy exposeAnnotationSerializationExclusionStrategy = new ExposeAnnotationSerializationExclusionStrategy(); - private static final ExposeAnnotationDeserializationExclusionStrategy + private static final ExposeAnnotationDeserializationExclusionStrategy exposeAnnotationDeserializationExclusionStrategy = new ExposeAnnotationDeserializationExclusionStrategy(); - + + private final Collection exclusionStrategies = + new HashSet(); + private double ignoreVersionsAfter; private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy; private boolean serializeInnerClasses; @@ -86,6 +89,10 @@ public final class GsonBuilder { * {@link #create()}. */ public GsonBuilder() { + // add default exclusion strategies + exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY); + exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY); + // setup default values ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS; serializeInnerClasses = true; @@ -129,17 +136,16 @@ public final class GsonBuilder { * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern */ public GsonBuilder excludeFieldsWithModifiers(int... modifiers) { - boolean skipSynthetics = true; - modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(skipSynthetics, modifiers); + modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(modifiers); return this; } /** * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some - * special text. This prevents attacks from third-party sites through script sourcing. See - * Gson Issue 42 - * for details. - * + * special text. This prevents attacks from third-party sites through script sourcing. See + * Gson Issue 42 + * for details. + * * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 */ @@ -147,7 +153,7 @@ public final class GsonBuilder { this.generateNonExecutableJson = true; return this; } - + /** * Configures Gson to exclude all fields from consideration for serialization or deserialization * that do not have the {@link com.google.gson.annotations.Expose} annotation. @@ -216,8 +222,25 @@ public final class GsonBuilder { * @since 1.3 */ public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) { - this.fieldNamingPolicy = - new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy); + this.fieldNamingPolicy = + new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy); + 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 disjunctive rule. + * This means that if one of the {@code strategies} suggests that a field (or class) should be + * skipped then that field (or object) is skipped during serializaiton/deserialization. + * + * @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 + */ + GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) { + for (ExclusionStrategy strategy : strategies) { + exclusionStrategies.add(strategy); + } return this; } @@ -412,12 +435,13 @@ 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(); - List deserializationStrategies = new LinkedList(); + List serializationStrategies = + new LinkedList(exclusionStrategies); + List deserializationStrategies = + new LinkedList(exclusionStrategies); + serializationStrategies.add(modifierBasedExclusionStrategy); deserializationStrategies.add(modifierBasedExclusionStrategy); - serializationStrategies.add(anonAndLocalClassExclusionStrategy); - deserializationStrategies.add(anonAndLocalClassExclusionStrategy); if (!serializeInnerClasses) { serializationStrategies.add(innerClassExclusionStrategy); @@ -431,9 +455,9 @@ public final class GsonBuilder { serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy); deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy); } - ExclusionStrategy serializationExclusionStrategy = + ExclusionStrategy serializationExclusionStrategy = new DisjunctionExclusionStrategy(serializationStrategies); - ExclusionStrategy deserializationExclusionStrategy = + ExclusionStrategy deserializationExclusionStrategy = new DisjunctionExclusionStrategy(deserializationStrategies); ParameterizedTypeHandlerMap> customSerializers = serializers.copyOf(); @@ -449,17 +473,17 @@ public final class GsonBuilder { ParameterizedTypeHandlerMap> customInstanceCreators = instanceCreators.copyOf(); customInstanceCreators.registerIfAbsent(DefaultTypeAdapters.getDefaultInstanceCreators()); - + customSerializers.makeUnmodifiable(); customDeserializers.makeUnmodifiable(); instanceCreators.makeUnmodifiable(); - + MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators); JsonFormatter formatter = prettyPrinting ? new JsonPrintFormatter(escapeHtmlChars) : new JsonCompactFormatter(escapeHtmlChars); - Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy, - fieldNamingPolicy, objConstructor, formatter, serializeNulls, customSerializers, + Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy, + fieldNamingPolicy, objConstructor, formatter, serializeNulls, customSerializers, customDeserializers, generateNonExecutableJson); return gson; } @@ -476,7 +500,7 @@ public final class GsonBuilder { } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) { dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle); } - + if (dateTypeAdapter != null) { serializers.register(Date.class, dateTypeAdapter); deserializers.register(Date.class, dateTypeAdapter); diff --git a/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java b/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java index 8923fbc3..e125bfae 100644 --- a/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/InnerClassExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** @@ -26,8 +25,8 @@ import java.lang.reflect.Modifier; */ class InnerClassExclusionStrategy implements ExclusionStrategy { - public boolean shouldSkipField(Field f) { - return isInnerClass(f.getType()); + public boolean shouldSkipField(FieldAttributes f) { + return isInnerClass(f.getDeclaredClass()); } public boolean shouldSkipClass(Class clazz) { @@ -37,7 +36,7 @@ class InnerClassExclusionStrategy implements ExclusionStrategy { private boolean isInnerClass(Class clazz) { return clazz.isMemberClass() && !isStatic(clazz); } - + private boolean isStatic(Class clazz) { return (clazz.getModifiers() & Modifier.STATIC) != 0; } diff --git a/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java b/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java index d64457f1..fdf8e5ba 100644 --- a/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/ModifierBasedExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; import java.util.Collection; import java.util.HashSet; @@ -28,11 +27,9 @@ import java.util.HashSet; * @author Joel Leitch */ final class ModifierBasedExclusionStrategy implements ExclusionStrategy { - private final boolean skipSyntheticField; private final Collection modifiers; - public ModifierBasedExclusionStrategy(boolean skipSyntheticFields, int... modifiers) { - this.skipSyntheticField = skipSyntheticFields; + public ModifierBasedExclusionStrategy(int... modifiers) { this.modifiers = new HashSet(); if (modifiers != null) { for (int modifier : modifiers) { @@ -41,13 +38,9 @@ final class ModifierBasedExclusionStrategy implements ExclusionStrategy { } } - public boolean shouldSkipField(Field f) { - if (skipSyntheticField && f.isSynthetic()) { - return true; - } - int objectModifiers = f.getModifiers(); + public boolean shouldSkipField(FieldAttributes f) { for (int modifier : modifiers) { - if ((objectModifiers & modifier) != 0) { + if (f.hasModifier(modifier)) { return true; } } diff --git a/gson/src/main/java/com/google/gson/NullExclusionStrategy.java b/gson/src/main/java/com/google/gson/NullExclusionStrategy.java index 38b9a44b..c7a1bafa 100644 --- a/gson/src/main/java/com/google/gson/NullExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/NullExclusionStrategy.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; /** * This acts as a "Null Object" pattern for the {@link ExclusionStrategy}. @@ -28,7 +27,7 @@ import java.lang.reflect.Field; */ final class NullExclusionStrategy implements ExclusionStrategy { - public boolean shouldSkipField(Field f) { + public boolean shouldSkipField(FieldAttributes f) { 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 118442f6..aa0da613 100644 --- a/gson/src/main/java/com/google/gson/ObjectNavigator.java +++ b/gson/src/main/java/com/google/gson/ObjectNavigator.java @@ -62,7 +62,7 @@ final class ObjectNavigator { * This is called to visit a field of the current object using a custom handler */ public boolean visitFieldUsingCustomHandler(Field f, Type actualTypeOfField, Object parent); - + /** * Retrieve the current target */ @@ -102,7 +102,7 @@ final class ObjectNavigator { if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) { return; } - visitor.start(objTypePair); + visitor.start(objTypePair); try { if (objTypeInfo.isArray()) { visitor.visitArray(objectToVisit, objTypePair.getType()); @@ -141,12 +141,12 @@ final class ObjectNavigator { Field[] fields = clazz.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); for (Field f : fields) { - if (exclusionStrategy.shouldSkipField(f)) { + if (exclusionStrategy.shouldSkipField(new FieldAttributes(f))) { continue; // skip } else { TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.getType()); Type actualTypeOfField = fieldTypeInfo.getActualType(); - boolean visitedWithCustomHandler = + boolean visitedWithCustomHandler = visitor.visitFieldUsingCustomHandler(f, actualTypeOfField, obj); if (!visitedWithCustomHandler) { if (fieldTypeInfo.isArray()) { diff --git a/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java b/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java new file mode 100644 index 00000000..ab90c5d0 --- /dev/null +++ b/gson/src/main/java/com/google/gson/SyntheticFieldExclusionStrategy.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 data object that stores attributes of a field. + * + *

    This class is immutable; therefore, it can be safely shared across threads. + * + * @author Inderjeet Singh + * @author Joel Leitch + * + * @since 1.4 + */ +class SyntheticFieldExclusionStrategy implements ExclusionStrategy { + private final boolean skipSyntheticFields; + + SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) { + this.skipSyntheticFields = skipSyntheticFields; + } + + public boolean shouldSkipClass(Class clazz) { + return false; + } + + public boolean shouldSkipField(FieldAttributes f) { + 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 60f36ece..8bd726f3 100644 --- a/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java +++ b/gson/src/main/java/com/google/gson/VersionExclusionStrategy.java @@ -19,9 +19,6 @@ package com.google.gson; import com.google.gson.annotations.Since; import com.google.gson.annotations.Until; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; - /** * This strategy will exclude any files and/or class that are passed the * {@link #version} value. @@ -36,36 +33,31 @@ final class VersionExclusionStrategy implements ExclusionStrategy { this.version = version; } - public boolean shouldSkipField(Field f) { - return !isValidVersion(f.getAnnotations()); + public boolean shouldSkipField(FieldAttributes f) { + return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class)); } public boolean shouldSkipClass(Class clazz) { - return !isValidVersion(clazz.getAnnotations()); + return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class)); } - private boolean isValidVersion(Annotation[] annotations) { - for (Annotation annotation : annotations) { - if (!isValidSince(annotation) || !isValidUntil(annotation)) { - return false; - } - } - return true; + private boolean isValidVersion(Since since, Until until) { + return (isValidSince(since) && isValidUntil(until)); } - - private boolean isValidSince(Annotation annotation) { - if (annotation instanceof Since) { - double annotationVersion = ((Since) annotation).value(); + + private boolean isValidSince(Since annotation) { + if (annotation != null) { + double annotationVersion = annotation.value(); if (annotationVersion > version) { return false; } } return true; } - - private boolean isValidUntil(Annotation annotation) { - if (annotation instanceof Until) { - double annotationVersion = ((Until) annotation).value(); + + private boolean isValidUntil(Until annotation) { + if (annotation != null) { + double annotationVersion = annotation.value(); if (annotationVersion <= version) { return false; } diff --git a/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java index e3333af3..b8c528ad 100644 --- a/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/DisjunctionExclusionStrategyTest.java @@ -16,15 +16,11 @@ package com.google.gson; -import com.google.gson.DisjunctionExclusionStrategy; -import com.google.gson.ExclusionStrategy; - -import junit.framework.TestCase; - -import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; +import junit.framework.TestCase; + /** * Unit tests for the {@link DisjunctionExclusionStrategy} class. * @@ -35,12 +31,13 @@ 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 Class CLAZZ = String.class; - private static final Field FIELD = CLAZZ.getFields()[0]; + private static final FieldAttributes FIELD = new FieldAttributes(CLAZZ.getFields()[0]); public void testBadInstantiation() throws Exception { try { List constructorParam = null; new DisjunctionExclusionStrategy(constructorParam); + fail("Should throw an exception"); } catch (IllegalArgumentException expected) { } } diff --git a/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java index 9dfcb13f..6de26ba3 100644 --- a/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/ExposeAnnotationDeserializationExclusionStrategyTest.java @@ -39,25 +39,25 @@ public class ExposeAnnotationDeserializationExclusionStrategyTest extends TestCa public void testNeverSkipClasses() throws Exception { assertFalse(strategy.shouldSkipClass(MockObject.class)); } - + public void testSkipNonAnnotatedFields() throws Exception { Field f = MockObject.class.getField("hiddenField"); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } - + public void testSkipExplicitlySkippedFields() throws Exception { Field f = MockObject.class.getField("explicitlyHiddenField"); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } - + public void testNeverSkipExposedAnnotatedFields() throws Exception { Field f = MockObject.class.getField("exposedField"); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { Field f = MockObject.class.getField("explicitlyExposedField"); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } @SuppressWarnings("unused") @@ -67,7 +67,7 @@ public class ExposeAnnotationDeserializationExclusionStrategyTest extends TestCa @Expose(deserialize=true) public final int explicitlyExposedField = 0; - + @Expose(deserialize=false) public final int explicitlyHiddenField = 0; diff --git a/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java index a07512e5..4974719f 100644 --- a/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/ExposeAnnotationSerializationExclusionStrategyTest.java @@ -39,25 +39,25 @@ public class ExposeAnnotationSerializationExclusionStrategyTest extends TestCase public void testNeverSkipClasses() throws Exception { assertFalse(strategy.shouldSkipClass(MockObject.class)); } - + public void testSkipNonAnnotatedFields() throws Exception { Field f = MockObject.class.getField("hiddenField"); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } - + public void testSkipExplicitlySkippedFields() throws Exception { Field f = MockObject.class.getField("explicitlyHiddenField"); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } - + public void testNeverSkipExposedAnnotatedFields() throws Exception { Field f = MockObject.class.getField("exposedField"); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } public void testNeverSkipExplicitlyExposedAnnotatedFields() throws Exception { Field f = MockObject.class.getField("explicitlyExposedField"); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } @SuppressWarnings("unused") @@ -67,7 +67,7 @@ public class ExposeAnnotationSerializationExclusionStrategyTest extends TestCase @Expose(serialize=true) public final int explicitlyExposedField = 0; - + @Expose(serialize=false) public final int explicitlyHiddenField = 0; diff --git a/gson/src/test/java/com/google/gson/FieldAttributesTest.java b/gson/src/test/java/com/google/gson/FieldAttributesTest.java new file mode 100644 index 00000000..212c9fd5 --- /dev/null +++ b/gson/src/test/java/com/google/gson/FieldAttributesTest.java @@ -0,0 +1,77 @@ +/* + * 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.Modifier; +import java.lang.reflect.Type; +import java.util.List; + +import junit.framework.TestCase; + +import com.google.gson.reflect.TypeToken; + +/** + * Unit tests for the {@link FieldAttributes} class. + * + * @author Inderjeet Singh + * @author Joel Leitch + */ +public class FieldAttributesTest extends TestCase { + private FieldAttributes fieldAttributes; + + @Override + protected void setUp() throws Exception { + super.setUp(); + fieldAttributes = new FieldAttributes(Foo.class.getField("bar")); + } + + public void testNullField() throws Exception { + try { + new FieldAttributes(null); + fail("Field parameter can not be null"); + } catch (IllegalArgumentException expected) { } + } + + public void testModifiers() throws Exception { + assertFalse(fieldAttributes.hasModifier(Modifier.STATIC)); + assertFalse(fieldAttributes.hasModifier(Modifier.FINAL)); + assertFalse(fieldAttributes.hasModifier(Modifier.ABSTRACT)); + assertFalse(fieldAttributes.hasModifier(Modifier.VOLATILE)); + assertFalse(fieldAttributes.hasModifier(Modifier.PROTECTED)); + + assertTrue(fieldAttributes.hasModifier(Modifier.PUBLIC)); + assertTrue(fieldAttributes.hasModifier(Modifier.TRANSIENT)); + } + + public void testIsSynthetic() throws Exception { + assertFalse(fieldAttributes.isSynthetic()); + } + + public void testName() throws Exception { + assertEquals("bar", fieldAttributes.getName()); + } + + public void testDeclaredTypeAndClass() throws Exception { + Type expectedType = new TypeToken>() {}.getType(); + assertEquals(expectedType, fieldAttributes.getDeclaredType()); + assertEquals(List.class, fieldAttributes.getDeclaredClass()); + } + + private static class Foo { + public transient List bar; + } +} diff --git a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java index 93e6be5b..790703be 100644 --- a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java +++ b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java @@ -16,11 +16,13 @@ package com.google.gson; -import com.google.gson.common.TestTypes.ClassWithNoFields; +import java.lang.reflect.Modifier; +import java.util.LinkedList; import junit.framework.TestCase; -import java.lang.reflect.Modifier; +import com.google.gson.common.TestTypes; +import com.google.gson.common.TestTypes.ClassWithNoFields; /** * Functional tests for Gson that depend on some internal package-protected elements of @@ -32,11 +34,45 @@ import java.lang.reflect.Modifier; */ public class FunctionWithInternalDependenciesTest extends TestCase { - public void testAnonymousLocalClassesSerialization() { - Gson gson = new Gson(new ModifierBasedExclusionStrategy( - true, Modifier.TRANSIENT, Modifier.STATIC), Gson.DEFAULT_NAMING_POLICY); + public void testAnonymousLocalClassesSerialization() throws Exception { + 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, + new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), + Gson.DEFAULT_JSON_FORMATTER, false, DefaultTypeAdapters.getDefaultSerializers(), + DefaultTypeAdapters.getDefaultDeserializers(), Gson.DEFAULT_JSON_NON_EXECUTABLE); assertEquals("{}", gson.toJson(new ClassWithNoFields() { // 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 ExclusionStrategy { + private final Class excludedThisClass; + + UserDefinedExclusionStrategy(Class excludedThisClass) { + this.excludedThisClass = excludedThisClass; + } + + public boolean shouldSkipClass(Class clazz) { + return excludedThisClass.equals(clazz); + } + + public boolean shouldSkipField(FieldAttributes f) { + 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 bff2a6af..4abfeaae 100644 --- a/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/InnerClassExclusionStrategyTest.java @@ -30,7 +30,7 @@ public class InnerClassExclusionStrategyTest extends TestCase { public StaticNestedClass staticNestedClass; private InnerClassExclusionStrategy strategy; - + @Override protected void setUp() throws Exception { super.setUp(); @@ -43,25 +43,25 @@ public class InnerClassExclusionStrategyTest extends TestCase { Class clazz = innerClass.getClass(); assertTrue(strategy.shouldSkipClass(clazz)); } - + public void testExcludeInnerClassField() throws Exception { Field f = getClass().getField("innerClass"); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } - + public void testIncludeStaticNestedClassObject() throws Exception { Class clazz = staticNestedClass.getClass(); assertFalse(strategy.shouldSkipClass(clazz)); } - + public void testIncludeStaticNestedClassField() throws Exception { Field f = getClass().getField("staticNestedClass"); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } - + class InnerClass { } - + static class StaticNestedClass { } } diff --git a/gson/src/test/java/com/google/gson/MockExclusionStrategy.java b/gson/src/test/java/com/google/gson/MockExclusionStrategy.java index 674148bc..6b7a3bab 100644 --- a/gson/src/test/java/com/google/gson/MockExclusionStrategy.java +++ b/gson/src/test/java/com/google/gson/MockExclusionStrategy.java @@ -16,13 +16,10 @@ package com.google.gson; -import com.google.gson.ExclusionStrategy; - -import java.lang.reflect.Field; /** * This is a configurable {@link ExclusionStrategy} that can be used for - * unit testing. + * unit testing. * * @author Joel Leitch */ @@ -35,7 +32,7 @@ public class MockExclusionStrategy implements ExclusionStrategy { this.skipField = skipField; } - public boolean shouldSkipField(Field f) { + public boolean shouldSkipField(FieldAttributes f) { return skipField; } diff --git a/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java index 7b0eee5e..d888d7eb 100644 --- a/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/NullExclusionStrategyTest.java @@ -16,8 +16,6 @@ package com.google.gson; -import com.google.gson.NullExclusionStrategy; - import junit.framework.TestCase; /** @@ -39,6 +37,7 @@ public class NullExclusionStrategyTest extends TestCase { } public void testNeverSkipsField() throws Exception { - assertFalse(strategy.shouldSkipField("".getClass().getFields()[0])); + assertFalse(strategy.shouldSkipField( + new FieldAttributes("".getClass().getFields()[0]))); } } diff --git a/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java b/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java index cca213bc..2034b4eb 100644 --- a/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java +++ b/gson/src/test/java/com/google/gson/VersionExclusionStrategyTest.java @@ -16,11 +16,11 @@ package com.google.gson; -import com.google.gson.annotations.Since; +import java.lang.reflect.Field; import junit.framework.TestCase; -import java.lang.reflect.Field; +import com.google.gson.annotations.Since; /** * Unit tests for the {@link VersionExclusionStrategy} class. @@ -41,27 +41,27 @@ public class VersionExclusionStrategyTest extends TestCase { Class clazz = MockObject.class; Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION); - + assertFalse(strategy.shouldSkipClass(clazz)); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } public void testClassAndFieldAreBehindInVersion() throws Exception { Class clazz = MockObject.class; Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION + 1); - + assertFalse(strategy.shouldSkipClass(clazz)); - assertFalse(strategy.shouldSkipField(f)); + assertFalse(strategy.shouldSkipField(new FieldAttributes(f))); } public void testClassAndFieldAreAheadInVersion() throws Exception { Class clazz = MockObject.class; Field f = clazz.getField("someField"); VersionExclusionStrategy strategy = new VersionExclusionStrategy(VERSION - 1); - + assertTrue(strategy.shouldSkipClass(clazz)); - assertTrue(strategy.shouldSkipField(f)); + assertTrue(strategy.shouldSkipField(new FieldAttributes(f))); } @Since(VERSION)