From e3af076ff271968a1a639c5bbdc1ba967b11ea94 Mon Sep 17 00:00:00 2001 From: Joel Leitch Date: Sat, 9 Jan 2010 22:43:27 +0000 Subject: [PATCH] Deprecate the FieldNamingStrategy interface and replace it with FieldNamingStrategy2. This is the first step to help make it easy to cache field annotations across all instances of a class, etc. --- .../gson/CamelCaseSeparatorNamingPolicy.java | 4 +- .../gson/CircularReferenceException.java | 5 +- .../gson/CompositionFieldNamingPolicy.java | 3 +- .../java/com/google/gson/FieldAttributes.java | 58 ++++++++++++++++--- .../com/google/gson/FieldNamingPolicy.java | 6 +- .../com/google/gson/FieldNamingStrategy.java | 2 + .../com/google/gson/FieldNamingStrategy2.java | 39 +++++++++++++ .../gson/FieldNamingStrategy2Adapter.java | 37 ++++++++++++ gson/src/main/java/com/google/gson/Gson.java | 6 +- .../java/com/google/gson/GsonBuilder.java | 16 ++++- .../google/gson/JavaFieldNamingPolicy.java | 3 +- .../gson/JsonArrayDeserializationVisitor.java | 7 +-- .../JsonObjectDeserializationVisitor.java | 11 ++-- .../google/gson/JsonSerializationVisitor.java | 17 +++--- .../google/gson/LowerCaseNamingPolicy.java | 7 ++- .../gson/ModifyFirstLetterNamingPolicy.java | 4 +- .../java/com/google/gson/ObjectNavigator.java | 44 ++++++++------ .../google/gson/ObjectNavigatorFactory.java | 6 +- gson/src/main/java/com/google/gson/Pair.java | 32 +++++++++- .../gson/RecursiveFieldNamingPolicy.java | 10 ++-- ...ameAnnotationInterceptingNamingPolicy.java | 10 ++-- .../google/gson/UpperCaseNamingPolicy.java | 3 +- .../gson/JavaFieldNamingPolicyTest.java | 6 +- ...nnotationInterceptingNamingPolicyTest.java | 8 +-- .../functional/CustomTypeAdaptersTest.java | 1 - 25 files changed, 258 insertions(+), 87 deletions(-) create mode 100644 gson/src/main/java/com/google/gson/FieldNamingStrategy2.java create mode 100644 gson/src/main/java/com/google/gson/FieldNamingStrategy2Adapter.java diff --git a/gson/src/main/java/com/google/gson/CamelCaseSeparatorNamingPolicy.java b/gson/src/main/java/com/google/gson/CamelCaseSeparatorNamingPolicy.java index 33457ef8..73242b76 100644 --- a/gson/src/main/java/com/google/gson/CamelCaseSeparatorNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/CamelCaseSeparatorNamingPolicy.java @@ -18,6 +18,7 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * Converts the field name that uses camel-case define word separation into separate words that @@ -56,7 +57,8 @@ final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy { } @Override - protected String translateName(String target, Type fieldType, Annotation[] annnotations) { + protected String translateName(String target, Type fieldType, + Collection annnotations) { StringBuilder translation = new StringBuilder(); for (int i = 0; i < target.length(); i++) { char character = target.charAt(i); diff --git a/gson/src/main/java/com/google/gson/CircularReferenceException.java b/gson/src/main/java/com/google/gson/CircularReferenceException.java index 52840a2b..301f5148 100644 --- a/gson/src/main/java/com/google/gson/CircularReferenceException.java +++ b/gson/src/main/java/com/google/gson/CircularReferenceException.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.gson; -import java.lang.reflect.Field; +package com.google.gson; /** * Exception class to indicate a circular reference error. @@ -33,7 +32,7 @@ final class CircularReferenceException extends RuntimeException { this.offendingNode = offendingNode; } - public IllegalStateException createDetailedException(Field offendingField) { + public IllegalStateException createDetailedException(FieldAttributes offendingField) { StringBuilder msg = new StringBuilder(getMessage()); if (offendingField != null) { msg.append("\n ").append("Offending field: ").append(offendingField.getName() + "\n"); diff --git a/gson/src/main/java/com/google/gson/CompositionFieldNamingPolicy.java b/gson/src/main/java/com/google/gson/CompositionFieldNamingPolicy.java index 652168c7..c6d252cd 100644 --- a/gson/src/main/java/com/google/gson/CompositionFieldNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/CompositionFieldNamingPolicy.java @@ -18,6 +18,7 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * Performs numerous field naming translations wrapped up as one object. @@ -36,7 +37,7 @@ abstract class CompositionFieldNamingPolicy extends RecursiveFieldNamingPolicy { } @Override - protected String translateName(String target, Type fieldType, Annotation[] annotations) { + protected String translateName(String target, Type fieldType, Collection annotations) { for (RecursiveFieldNamingPolicy policy : fieldPolicies) { target = policy.translateName(target, fieldType, annotations); } diff --git a/gson/src/main/java/com/google/gson/FieldAttributes.java b/gson/src/main/java/com/google/gson/FieldAttributes.java index 300ed6b3..9ad239b9 100644 --- a/gson/src/main/java/com/google/gson/FieldAttributes.java +++ b/gson/src/main/java/com/google/gson/FieldAttributes.java @@ -19,6 +19,9 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; /** * A data object that stores attributes of a field. @@ -35,11 +38,11 @@ public final class FieldAttributes { private final Class declaredType; private final boolean isSynthetic; private final int modifiers; + private final String name; // Fields used for lazy initialization - private String name; private Type genericType; - private Annotation[] annotations; + private Collection annotations; /** * Constructs a Field Attributes object from the {@code f}. @@ -49,6 +52,7 @@ public final class FieldAttributes { FieldAttributes(final Field f) { Preconditions.checkNotNull(f); field = f; + name = field.getName(); declaredType = f.getType(); isSynthetic = f.isSynthetic(); modifiers = field.getModifiers(); @@ -58,9 +62,6 @@ public final class FieldAttributes { * @return the name of the field */ public String getName() { - if (name == null) { - name = field.getName(); - } return name; } @@ -115,10 +116,21 @@ public final class FieldAttributes { * @return the annotation instance if it is bound to the field; otherwise {@code null} */ public T getAnnotation(Class annotation) { + return getAnnotationFromArray(getAnnotations(), annotation); + } + + /** + * Return the annotations that are present on this field. + * + * @return an array of all the annotations set on the field + * @since 1.4 + */ + public Collection getAnnotations() { if (annotations == null) { - annotations = field.getAnnotations(); + annotations = Collections.unmodifiableCollection( + Arrays.asList(field.getAnnotations())); } - return getAnnotationFromArray(annotations, annotation); + return annotations; } /** @@ -135,6 +147,28 @@ public final class FieldAttributes { return (modifiers & modifier) != 0; } + /** + * This is exposed internally only for the removing synthetic fields from the JSON output. + * + * @return true if the field is synthetic; otherwise false + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + void set(Object instance, Object value) throws IllegalAccessException { + field.set(instance, value); + } + + /** + * This is exposed internally only for the removing synthetic fields from the JSON output. + * + * @return true if the field is synthetic; otherwise false + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + Object get(Object instance) throws IllegalAccessException { + return field.get(instance); + } + /** * This is exposed internally only for the removing synthetic fields from the JSON output. * @@ -143,10 +177,18 @@ public final class FieldAttributes { boolean isSynthetic() { return isSynthetic; } + + /** + * @deprecated remove this when {@link FieldNamingStrategy} is deleted. + */ + @Deprecated + Field getFieldObject() { + return field; + } @SuppressWarnings("unchecked") private static T getAnnotationFromArray( - Annotation[] annotations, Class annotation) { + Collection annotations, Class annotation) { for (Annotation a : annotations) { if (a.annotationType() == annotation) { return (T) a; diff --git a/gson/src/main/java/com/google/gson/FieldNamingPolicy.java b/gson/src/main/java/com/google/gson/FieldNamingPolicy.java index e1826243..17faa30e 100644 --- a/gson/src/main/java/com/google/gson/FieldNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/FieldNamingPolicy.java @@ -72,13 +72,13 @@ public enum FieldNamingPolicy { */ LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-")); - private final FieldNamingStrategy namingPolicy; + private final FieldNamingStrategy2 namingPolicy; - private FieldNamingPolicy(FieldNamingStrategy namingPolicy) { + private FieldNamingPolicy(FieldNamingStrategy2 namingPolicy) { this.namingPolicy = namingPolicy; } - FieldNamingStrategy getFieldNamingPolicy() { + FieldNamingStrategy2 getFieldNamingPolicy() { return namingPolicy; } } diff --git a/gson/src/main/java/com/google/gson/FieldNamingStrategy.java b/gson/src/main/java/com/google/gson/FieldNamingStrategy.java index 9be453ad..b37444ef 100644 --- a/gson/src/main/java/com/google/gson/FieldNamingStrategy.java +++ b/gson/src/main/java/com/google/gson/FieldNamingStrategy.java @@ -26,7 +26,9 @@ import java.lang.reflect.Field; * @author Inderjeet Singh * @author Joel Leitch * @since 1.3 + * @deprecated use {@link FieldNamingStrategy2} instead */ +@Deprecated public interface FieldNamingStrategy { /** diff --git a/gson/src/main/java/com/google/gson/FieldNamingStrategy2.java b/gson/src/main/java/com/google/gson/FieldNamingStrategy2.java new file mode 100644 index 00000000..b1d986cf --- /dev/null +++ b/gson/src/main/java/com/google/gson/FieldNamingStrategy2.java @@ -0,0 +1,39 @@ +/* + * 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. + * 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; + +/** + * The new mechanism for providing custom field naming in Gson. This allows the client code + * to translate field names into a particular convention that is not supported as a normal + * Java field declaration rules. For example, Java does not support "-" characters in a + * field name. + * + * @author Inderjeet Singh + * @author Joel Leitch + * @since 1.4 + */ +public interface FieldNamingStrategy2 { + + /** + * Translates the field name into its JSON field name representation. + * + * @param f the field that is being translated + * @return the translated field name. + * @since 1.3 + */ + public String translateName(FieldAttributes f); +} diff --git a/gson/src/main/java/com/google/gson/FieldNamingStrategy2Adapter.java b/gson/src/main/java/com/google/gson/FieldNamingStrategy2Adapter.java new file mode 100644 index 00000000..9ef614a7 --- /dev/null +++ b/gson/src/main/java/com/google/gson/FieldNamingStrategy2Adapter.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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 "deprecated" {@link FieldNamingStrategy} to the new {@link FieldNamingStrategy2} + * type. + * + * @author Inderjeet Singh + * @author Joel Leitch + */ +class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 { + private final FieldNamingStrategy adaptee; + + public FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) { + Preconditions.checkNotNull(adaptee); + this.adaptee = adaptee; + } + + public String translateName(FieldAttributes f) { + return adaptee.translateName(f.getFieldObject()); + } +} diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 4c03c2bd..a2dd9c52 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -86,7 +86,7 @@ public final class Gson { static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY = new ModifierBasedExclusionStrategy(new int[] { Modifier.TRANSIENT, Modifier.STATIC }); static final JsonFormatter DEFAULT_JSON_FORMATTER = new JsonCompactFormatter(); - static final FieldNamingStrategy DEFAULT_NAMING_POLICY = + static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY = new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy()); private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = @@ -98,7 +98,7 @@ public final class Gson { private final ExclusionStrategy deserializationStrategy; - private final FieldNamingStrategy fieldNamingPolicy; + private final FieldNamingStrategy2 fieldNamingPolicy; private final MappedObjectConstructor objectConstructor; /** Map containing Type or Class objects as keys */ @@ -154,7 +154,7 @@ public final class Gson { } Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy, - FieldNamingStrategy fieldNamingPolicy, MappedObjectConstructor objectConstructor, + FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor, JsonFormatter formatter, boolean serializeNulls, ParameterizedTypeHandlerMap> serializers, ParameterizedTypeHandlerMap> deserializers, diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index f49044e5..c0ad98e9 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -69,7 +69,7 @@ public final class GsonBuilder { private boolean serializeInnerClasses; private boolean excludeFieldsWithoutExposeAnnotation; private LongSerializationPolicy longSerializationPolicy; - private FieldNamingStrategy fieldNamingPolicy; + private FieldNamingStrategy2 fieldNamingPolicy; private final ParameterizedTypeHandlerMap> instanceCreators; private final ParameterizedTypeHandlerMap> serializers; private final ParameterizedTypeHandlerMap> deserializers; @@ -220,8 +220,22 @@ public final class GsonBuilder { * @param fieldNamingStrategy the actual naming strategy to apply to the fields * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @since 1.3 + * @deprecated use {@link #setFieldNamingStrategy(FieldNamingStrategy2)} instead. */ + @Deprecated public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) { + return setFieldNamingStrategy(new FieldNamingStrategy2Adapter(fieldNamingStrategy)); + } + + /** + * Configures Gson to apply a specific naming policy strategy to an object's field during + * serialization and deserialization. + * + * @param fieldNamingStrategy the actual naming strategy to apply to the fields + * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern + * @since 1.4 + */ + public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy2 fieldNamingStrategy) { this.fieldNamingPolicy = new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy); return this; diff --git a/gson/src/main/java/com/google/gson/JavaFieldNamingPolicy.java b/gson/src/main/java/com/google/gson/JavaFieldNamingPolicy.java index e2bb768d..83f16809 100644 --- a/gson/src/main/java/com/google/gson/JavaFieldNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/JavaFieldNamingPolicy.java @@ -18,6 +18,7 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * A simple implementation of the {@link FieldNamingStrategy} interface such that it does not @@ -44,7 +45,7 @@ import java.lang.reflect.Type; class JavaFieldNamingPolicy extends RecursiveFieldNamingPolicy { @Override - protected String translateName(String target, Type fieldType, Annotation[] annotations) { + protected String translateName(String target, Type fieldType, Collection annotations) { return target; } } diff --git a/gson/src/main/java/com/google/gson/JsonArrayDeserializationVisitor.java b/gson/src/main/java/com/google/gson/JsonArrayDeserializationVisitor.java index b885814e..72b269fe 100644 --- a/gson/src/main/java/com/google/gson/JsonArrayDeserializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonArrayDeserializationVisitor.java @@ -17,7 +17,6 @@ package com.google.gson; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.lang.reflect.Type; /** @@ -91,17 +90,17 @@ final class JsonArrayDeserializationVisitor extends JsonDeserializationVisito throw new JsonParseException("Expecting array but found object: " + node); } - public void visitArrayField(Field f, Type typeOfF, Object obj) { + public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) { throw new JsonParseException("Expecting array but found array field " + f.getName() + ": " + obj); } - public void visitObjectField(Field f, Type typeOfF, Object obj) { + public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) { throw new JsonParseException("Expecting array but found object field " + f.getName() + ": " + obj); } - public boolean visitFieldUsingCustomHandler(Field f, Type actualTypeOfField, Object parent) { + public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent) { throw new JsonParseException("Expecting array but found field " + f.getName() + ": " + parent); } diff --git a/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java b/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java index b3a2ea94..efdcbad2 100644 --- a/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java @@ -16,7 +16,6 @@ package com.google.gson; -import java.lang.reflect.Field; import java.lang.reflect.Type; /** @@ -50,7 +49,7 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit throw new JsonParseException("Expecting object but found array: " + array); } - public void visitObjectField(Field f, Type typeOfF, Object obj) { + public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) { try { if (!json.isJsonObject()) { throw new JsonParseException("Expecting object found: " + json); @@ -69,7 +68,7 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit } } - public void visitArrayField(Field f, Type typeOfF, Object obj) { + public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) { try { if (!json.isJsonObject()) { throw new JsonParseException("Expecting object found: " + json); @@ -88,12 +87,12 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit } } - private String getFieldName(Field f) { - FieldNamingStrategy namingPolicy = factory.getFieldNamingPolicy(); + private String getFieldName(FieldAttributes f) { + FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy(); return namingPolicy.translateName(f); } - public boolean visitFieldUsingCustomHandler(Field f, Type declaredTypeOfField, Object parent) { + public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) { try { String fName = getFieldName(f); if (!json.isJsonObject()) { diff --git a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java index d4722a18..04567590 100644 --- a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java @@ -17,7 +17,6 @@ package com.google.gson; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.lang.reflect.Type; /** @@ -84,7 +83,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { } } - public void visitArrayField(Field f, Type typeOfF, Object obj) { + public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) { try { if (isFieldNull(f, obj)) { if (serializeNulls) { @@ -99,7 +98,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { } } - public void visitObjectField(Field f, Type typeOfF, Object obj) { + public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) { try { if (isFieldNull(f, obj)) { if (serializeNulls) { @@ -122,13 +121,13 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { assignToRoot(json); } - private void addAsChildOfObject(Field f, ObjectTypePair fieldValuePair) { + private void addAsChildOfObject(FieldAttributes f, ObjectTypePair fieldValuePair) { JsonElement childElement = getJsonElementForChild(fieldValuePair); addChildAsElement(f, childElement); } - private void addChildAsElement(Field f, JsonElement childElement) { - FieldNamingStrategy namingPolicy = factory.getFieldNamingPolicy(); + private void addChildAsElement(FieldAttributes f, JsonElement childElement) { + FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy(); root.getAsJsonObject().add(namingPolicy.translateName(f), childElement); } @@ -191,7 +190,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { } } - public boolean visitFieldUsingCustomHandler(Field f, Type declaredTypeOfField, Object parent) { + public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) { try { Preconditions.checkState(root.isJsonObject()); Object obj = f.get(parent); @@ -221,11 +220,11 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { root = newRoot; } - private boolean isFieldNull(Field f, Object obj) { + private boolean isFieldNull(FieldAttributes f, Object obj) { return getFieldValue(f, obj) == null; } - private Object getFieldValue(Field f, Object obj) { + private Object getFieldValue(FieldAttributes f, Object obj) { try { return f.get(obj); } catch (IllegalAccessException e) { diff --git a/gson/src/main/java/com/google/gson/LowerCaseNamingPolicy.java b/gson/src/main/java/com/google/gson/LowerCaseNamingPolicy.java index bcc20607..3a3ce58a 100644 --- a/gson/src/main/java/com/google/gson/LowerCaseNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/LowerCaseNamingPolicy.java @@ -18,12 +18,13 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * A {@link FieldNamingStrategy} that ensures the JSON field names consist of only * lower case letters. * - *

The following is an example:

+ *

The following is an example:

*
  * class IntWrapper {
  *   public int integerField = 0;
@@ -36,12 +37,14 @@ import java.lang.reflect.Type;
  * assert("integerfield".equals(translatedFieldName));
  * 
* + * @author Inderjeet Singh * @author Joel Leitch */ class LowerCaseNamingPolicy extends RecursiveFieldNamingPolicy { @Override - protected String translateName(String target, Type fieldType, Annotation[] annotations) { + protected String translateName(String target, Type fieldType, + Collection annotations) { return target.toLowerCase(); } } diff --git a/gson/src/main/java/com/google/gson/ModifyFirstLetterNamingPolicy.java b/gson/src/main/java/com/google/gson/ModifyFirstLetterNamingPolicy.java index 768d6616..f611bdc6 100644 --- a/gson/src/main/java/com/google/gson/ModifyFirstLetterNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/ModifyFirstLetterNamingPolicy.java @@ -18,6 +18,7 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * A {@link FieldNamingStrategy} that ensures the JSON field names begins with @@ -67,7 +68,8 @@ class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy { } @Override - protected String translateName(String target, Type fieldType, Annotation[] annotations) { + protected String translateName(String target, Type fieldType, + Collection annotations) { StringBuilder fieldNameBuilder = new StringBuilder(); int index = 0; char firstCharacter = target.charAt(index); diff --git a/gson/src/main/java/com/google/gson/ObjectNavigator.java b/gson/src/main/java/com/google/gson/ObjectNavigator.java index cf46405a..c72ffa7f 100644 --- a/gson/src/main/java/com/google/gson/ObjectNavigator.java +++ b/gson/src/main/java/com/google/gson/ObjectNavigator.java @@ -21,8 +21,9 @@ import java.lang.reflect.Field; import java.lang.reflect.Type; /** - * Provides ability to apply a visitor to an object and all of its fields recursively. - * + * Provides ability to apply a visitor to an object and all of its fields + * recursively. + * * @author Inderjeet Singh * @author Joel Leitch */ @@ -30,10 +31,12 @@ final class ObjectNavigator { public interface Visitor { public void start(ObjectTypePair node); + public void end(ObjectTypePair node); /** - * This is called before the object navigator starts visiting the current object + * This is called before the object navigator starts visiting the current + * object */ void startVisitingObject(Object node); @@ -45,23 +48,26 @@ final class ObjectNavigator { /** * This is called to visit an object field of the current object */ - void visitObjectField(Field f, Type typeOfF, Object obj); + void visitObjectField(FieldAttributes f, Type typeOfF, Object obj); /** * This is called to visit an array field of the current object */ - void visitArrayField(Field f, Type typeOfF, Object obj); + void visitArrayField(FieldAttributes f, Type typeOfF, Object obj); /** * This is called to visit an object using a custom handler + * * @return true if a custom handler exists, false otherwise */ public boolean visitUsingCustomHandler(ObjectTypePair objTypePair); /** - * This is called to visit a field of the current object using a custom handler + * This is called to visit a field of the current object using a custom + * handler */ - public boolean visitFieldUsingCustomHandler(Field f, Type actualTypeOfField, Object parent); + public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, + Object parent); /** * Retrieve the current target @@ -75,9 +81,11 @@ final class ObjectNavigator { private final ObjectTypePair objTypePair; /** - * @param objTypePair The object,type (fully genericized) being navigated - * @param exclusionStrategy the concrete strategy object to be used to - * filter out fields of an object. + * @param objTypePair + * The object,type (fully genericized) being navigated + * @param exclusionStrategy + * the concrete strategy object to be used to filter out fields of an + * object. */ ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) { Preconditions.checkNotNull(exclusionStrategy); @@ -87,8 +95,8 @@ final class ObjectNavigator { } /** - * Navigate all the fields of the specified object. - * If a field is null, it does not get visited. + * Navigate all the fields of the specified object. If a field is null, it + * does not get visited. */ public void accept(Visitor visitor) { TypeInfo objTypeInfo = new TypeInfo(objTypePair.type); @@ -110,15 +118,15 @@ final class ObjectNavigator { } else if (objTypeInfo.getActualType() == Object.class && isPrimitiveOrString(objectToVisit)) { // TODO(Joel): this is only used for deserialization of "primitives" - // we should rethink this!!! + // we should rethink this!!! visitor.visitPrimitive(objectToVisit); objectToVisit = visitor.getTarget(); } else { visitor.startVisitingObject(objectToVisit); ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType(); Class topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass(); - for (Class curr = topLevelClass; curr != null && !curr.equals(Object.class); - curr = curr.getSuperclass()) { + for (Class curr = topLevelClass; curr != null && !curr.equals(Object.class); curr = + curr.getSuperclass()) { if (!curr.isSynthetic()) { navigateClassFields(objectToVisit, curr, visitor); } @@ -148,12 +156,12 @@ final class ObjectNavigator { TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type); Type declaredTypeOfField = fieldTypeInfo.getActualType(); boolean visitedWithCustomHandler = - visitor.visitFieldUsingCustomHandler(f, declaredTypeOfField, obj); + visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj); if (!visitedWithCustomHandler) { if (fieldTypeInfo.isArray()) { - visitor.visitArrayField(f, declaredTypeOfField, obj); + visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj); } else { - visitor.visitObjectField(f, declaredTypeOfField, obj); + visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj); } } } diff --git a/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java b/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java index 69fef7ce..3f90cea3 100644 --- a/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java +++ b/gson/src/main/java/com/google/gson/ObjectNavigatorFactory.java @@ -25,7 +25,7 @@ package com.google.gson; */ final class ObjectNavigatorFactory { private final ExclusionStrategy strategy; - private final FieldNamingStrategy fieldNamingPolicy; + private final FieldNamingStrategy2 fieldNamingPolicy; /** * Creates a factory object that will be able to create new @@ -36,7 +36,7 @@ final class ObjectNavigatorFactory { * @param fieldNamingPolicy the naming policy that should be applied to field * names */ - public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy fieldNamingPolicy) { + public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) { Preconditions.checkNotNull(fieldNamingPolicy); this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy); this.fieldNamingPolicy = fieldNamingPolicy; @@ -55,7 +55,7 @@ final class ObjectNavigatorFactory { return new ObjectNavigator(objTypePair, strategy); } - FieldNamingStrategy getFieldNamingPolicy() { + FieldNamingStrategy2 getFieldNamingPolicy() { return fieldNamingPolicy; } } diff --git a/gson/src/main/java/com/google/gson/Pair.java b/gson/src/main/java/com/google/gson/Pair.java index c9c48343..66799380 100644 --- a/gson/src/main/java/com/google/gson/Pair.java +++ b/gson/src/main/java/com/google/gson/Pair.java @@ -13,8 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.google.gson; +/** + * A simple object that holds onto a pair of object references, first and second. + * + * @author Inderjeet Singh + * @author Joel Leitch + * + * @param + * @param + */ final class Pair { final FIRST first; @@ -24,4 +34,24 @@ final class Pair { this.first = first; this.second = second; } -} + + @Override + public int hashCode() { + return 17 * ((first != null) ? first.hashCode() : 0) + + 17 * ((second != null) ? second.hashCode() : 0); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Pair)) { + return false; + } + + Pair that = (Pair) o; + return equal(this.first, that.first) && equal(this.second, that.second); + } + + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } +} \ No newline at end of file diff --git a/gson/src/main/java/com/google/gson/RecursiveFieldNamingPolicy.java b/gson/src/main/java/com/google/gson/RecursiveFieldNamingPolicy.java index fbdc002c..b0634b3f 100644 --- a/gson/src/main/java/com/google/gson/RecursiveFieldNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/RecursiveFieldNamingPolicy.java @@ -17,8 +17,8 @@ package com.google.gson; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; import java.lang.reflect.Type; +import java.util.Collection; /** * A mechanism for providing custom field naming in Gson. This allows the client code to translate @@ -27,11 +27,11 @@ import java.lang.reflect.Type; * * @author Joel Leitch */ -abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy { +abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 { - public final String translateName(Field f) { + public final String translateName(FieldAttributes f) { Preconditions.checkNotNull(f); - return translateName(f.getName(), f.getGenericType(), f.getAnnotations()); + return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations()); } /** @@ -42,5 +42,5 @@ abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy { * @param annotations the annotations set on the field * @return the translated field name */ - protected abstract String translateName(String target, Type fieldType, Annotation[] annotations); + protected abstract String translateName(String target, Type fieldType, Collection annotations); } diff --git a/gson/src/main/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicy.java b/gson/src/main/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicy.java index 0100dc69..bf898d3f 100644 --- a/gson/src/main/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicy.java @@ -18,8 +18,6 @@ package com.google.gson; import com.google.gson.annotations.SerializedName; -import java.lang.reflect.Field; - /** * A {@link FieldNamingStrategy} that acts as a chain of responsibility. If the * {@link com.google.gson.annotations.SerializedName} annotation is applied to a field then this @@ -33,15 +31,15 @@ import java.lang.reflect.Field; * * @author Joel Leitch */ -final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy { +final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 { private static final JsonFieldNameValidator fieldNameValidator = new JsonFieldNameValidator(); - private final FieldNamingStrategy delegate; + private final FieldNamingStrategy2 delegate; - public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy delegate) { + public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) { this.delegate = delegate; } - public String translateName(Field f) { + public String translateName(FieldAttributes f) { Preconditions.checkNotNull(f); SerializedName serializedName = f.getAnnotation(SerializedName.class); if (serializedName != null) { diff --git a/gson/src/main/java/com/google/gson/UpperCaseNamingPolicy.java b/gson/src/main/java/com/google/gson/UpperCaseNamingPolicy.java index cd18208a..1bb33f2e 100644 --- a/gson/src/main/java/com/google/gson/UpperCaseNamingPolicy.java +++ b/gson/src/main/java/com/google/gson/UpperCaseNamingPolicy.java @@ -18,6 +18,7 @@ package com.google.gson; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Collection; /** * A {@link FieldNamingStrategy} that ensures the JSON field names consist of only @@ -41,7 +42,7 @@ import java.lang.reflect.Type; class UpperCaseNamingPolicy extends RecursiveFieldNamingPolicy { @Override - protected String translateName(String target, Type fieldType, Annotation[] annotations) { + protected String translateName(String target, Type fieldType, Collection annotations) { return target.toUpperCase(); } } diff --git a/gson/src/test/java/com/google/gson/JavaFieldNamingPolicyTest.java b/gson/src/test/java/com/google/gson/JavaFieldNamingPolicyTest.java index cf51e076..1836bdf2 100644 --- a/gson/src/test/java/com/google/gson/JavaFieldNamingPolicyTest.java +++ b/gson/src/test/java/com/google/gson/JavaFieldNamingPolicyTest.java @@ -18,8 +18,6 @@ package com.google.gson; import junit.framework.TestCase; -import java.lang.reflect.Field; - /** * Tests for the {@link JavaFieldNamingPolicy} class. * @@ -36,13 +34,13 @@ public class JavaFieldNamingPolicyTest extends TestCase { } public void testFieldNamingPolicy() throws Exception { - Field f = String.class.getFields()[0]; + FieldAttributes f = new FieldAttributes(String.class.getFields()[0]); assertEquals(f.getName(), namingPolicy.translateName(f)); } public void testNullField() throws Exception { try { - namingPolicy.translateName((Field) null); + namingPolicy.translateName((FieldAttributes) null); fail("Should have thrown an exception"); } catch (IllegalArgumentException expected) { } } diff --git a/gson/src/test/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicyTest.java b/gson/src/test/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicyTest.java index a0144a58..7894663b 100644 --- a/gson/src/test/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicyTest.java +++ b/gson/src/test/java/com/google/gson/SerializedNameAnnotationInterceptingNamingPolicyTest.java @@ -16,11 +16,9 @@ package com.google.gson; -import com.google.gson.annotations.SerializedName; - import junit.framework.TestCase; -import java.lang.reflect.Field; +import com.google.gson.annotations.SerializedName; /** * Unit tests for the {@link SerializedNameAnnotationInterceptingNamingPolicy} class. @@ -40,7 +38,7 @@ public class SerializedNameAnnotationInterceptingNamingPolicyTest extends TestCa public void testFieldWithAnnotation() throws Exception { String fieldName = "fieldWithAnnotation"; - Field f = SomeObject.class.getField(fieldName); + FieldAttributes f = new FieldAttributes(SomeObject.class.getField(fieldName)); assertFalse(ANNOTATED_FIELD_NAME.equals(fieldName)); assertEquals(ANNOTATED_FIELD_NAME, policy.translateName(f)); @@ -48,7 +46,7 @@ public class SerializedNameAnnotationInterceptingNamingPolicyTest extends TestCa public void testFieldWithoutAnnotation() throws Exception { String fieldName = "fieldWithoutAnnotation"; - Field f = SomeObject.class.getField(fieldName); + FieldAttributes f = new FieldAttributes(SomeObject.class.getField(fieldName)); assertEquals(fieldName, policy.translateName(f)); } diff --git a/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java index e38109d4..015cf75e 100644 --- a/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java @@ -426,7 +426,6 @@ public class CustomTypeAdaptersTest extends TestCase { } private static class DataHolder { - @SuppressWarnings("unused") final String data; // For use by Gson