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.
This commit is contained in:
parent
7079799890
commit
e3af076ff2
@ -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<Annotation> annnotations) {
|
||||
StringBuilder translation = new StringBuilder();
|
||||
for (int i = 0; i < target.length(); i++) {
|
||||
char character = target.charAt(i);
|
||||
|
@ -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");
|
||||
|
@ -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<Annotation> annotations) {
|
||||
for (RecursiveFieldNamingPolicy policy : fieldPolicies) {
|
||||
target = policy.translateName(target, fieldType, annotations);
|
||||
}
|
||||
|
@ -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<Annotation> 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 extends Annotation> T getAnnotation(Class<T> 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<Annotation> 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 extends Annotation> T getAnnotationFromArray(
|
||||
Annotation[] annotations, Class<T> annotation) {
|
||||
Collection<Annotation> annotations, Class<T> annotation) {
|
||||
for (Annotation a : annotations) {
|
||||
if (a.annotationType() == annotation) {
|
||||
return (T) a;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
39
gson/src/main/java/com/google/gson/FieldNamingStrategy2.java
Normal file
39
gson/src/main/java/com/google/gson/FieldNamingStrategy2.java
Normal file
@ -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);
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
|
@ -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<InstanceCreator<?>> instanceCreators;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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;
|
||||
|
@ -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<Annotation> annotations) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
@ -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<T> 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);
|
||||
}
|
||||
|
@ -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<T> 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<T> 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<T> 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()) {
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
@ -36,12 +37,14 @@ import java.lang.reflect.Type;
|
||||
* assert("integerfield".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @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<Annotation> annotations) {
|
||||
return target.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
@ -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<Annotation> annotations) {
|
||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
||||
int index = 0;
|
||||
char firstCharacter = target.charAt(index);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 <FIRST>
|
||||
* @param <SECOND>
|
||||
*/
|
||||
final class Pair<FIRST, SECOND> {
|
||||
|
||||
final FIRST first;
|
||||
@ -24,4 +34,24 @@ final class Pair<FIRST, SECOND> {
|
||||
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));
|
||||
}
|
||||
}
|
@ -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<Annotation> annotations);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<Annotation> annotations) {
|
||||
return target.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
@ -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) { }
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -426,7 +426,6 @@ public class CustomTypeAdaptersTest extends TestCase {
|
||||
}
|
||||
|
||||
private static class DataHolder {
|
||||
@SuppressWarnings("unused")
|
||||
final String data;
|
||||
|
||||
// For use by Gson
|
||||
|
Loading…
Reference in New Issue
Block a user