Revised ancestor stack to use both object and type

This commit is contained in:
Inderjeet Singh 2009-10-03 04:45:12 +00:00
parent fbf834c3f6
commit 2716d96516
10 changed files with 114 additions and 68 deletions

View File

@ -60,7 +60,7 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
JsonDeserializationContext context) throws JsonParseException {
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
ObjectNavigator on = navigatorFactory.create(null, arrayType);
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType));
on.accept(visitor);
return visitor.getTarget();
}
@ -69,7 +69,7 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
ObjectNavigator on = navigatorFactory.create(null, typeOfT);
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT));
on.accept(visitor);
return visitor.getTarget();
}
@ -79,7 +79,7 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
json, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
ObjectNavigator on = navigatorFactory.create(json.getAsObject(), typeOfT);
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT));
on.accept(visitor);
Object target = visitor.getTarget();
return (T) target;

View File

@ -58,14 +58,15 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
protected abstract T constructTarget();
public void start(Object node) {
public void start(ObjectTypePair node) {
}
public void end(Object node) {
public void end(ObjectTypePair node) {
}
@SuppressWarnings("unchecked")
public final boolean visitUsingCustomHandler(Object obj, Type objType) {
public final boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
Type objType = objTypePair.getType();
JsonDeserializer deserializer = deserializers.getHandlerFor(objType);
if (deserializer != null) {
target = (T) deserializer.deserialize(json, objType, context);
@ -89,7 +90,7 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
}
private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) {
ObjectNavigator on = factory.create(null, type);
ObjectNavigator on = factory.create(new ObjectTypePair(null, type));
on.accept(childVisitor);
// the underlying object may have changed during the construction phase
// This happens primarily because of custom deserializers

View File

@ -28,14 +28,14 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
private final ObjectNavigatorFactory factory;
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
private final boolean serializeNulls;
private final MemoryRefStack<Object> ancestors;
private final MemoryRefStack ancestors;
JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) {
this.factory = factory;
this.serializeNulls = serializeNulls;
this.serializers = serializers;
this.ancestors = new MemoryRefStack<Object>();
this.ancestors = new MemoryRefStack();
}
public JsonElement serialize(Object src) {
@ -43,7 +43,7 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
}
public JsonElement serialize(Object src, Type typeOfSrc) {
ObjectNavigator on = factory.create(src, typeOfSrc);
ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc));
JsonSerializationVisitor visitor =
new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors);
on.accept(visitor);

View File

@ -32,12 +32,12 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
private final boolean serializeNulls;
private final JsonSerializationContext context;
private final MemoryRefStack<Object> ancestors;
private final MemoryRefStack ancestors;
private JsonElement root;
JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
JsonSerializationContext context, MemoryRefStack<Object> ancestors) {
JsonSerializationContext context, MemoryRefStack ancestors) {
this.factory = factory;
this.serializeNulls = serializeNulls;
this.serializers = serializers;
@ -49,7 +49,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
return null;
}
public void start(Object node) {
public void start(ObjectTypePair node) {
if (node == null) {
return;
}
@ -59,7 +59,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
ancestors.push(node);
}
public void end(Object node) {
public void end(ObjectTypePair node) {
if (node != null) {
ancestors.pop();
}
@ -80,7 +80,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
if (child != null) {
childType = getActualTypeIfMoreSpecific(childType, child.getClass());
}
addAsArrayElement(childType, child);
addAsArrayElement(new ObjectTypePair(child, childType));
}
}
@ -92,7 +92,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
} else {
Object array = getFieldValue(f, obj);
addAsChildOfObject(f, typeOfF, array);
addAsChildOfObject(f, new ObjectTypePair(array, typeOfF));
}
} catch (CircularReferenceException e) {
throw e.createDetailedException(f);
@ -110,7 +110,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
if (fieldValue != null) {
typeOfF = getActualTypeIfMoreSpecific(typeOfF, fieldValue.getClass());
}
addAsChildOfObject(f, typeOfF, fieldValue);
addAsChildOfObject(f, new ObjectTypePair(fieldValue, typeOfF));
}
} catch (CircularReferenceException e) {
throw e.createDetailedException(f);
@ -139,8 +139,8 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
assignToRoot(json);
}
private void addAsChildOfObject(Field f, Type fieldType, Object fieldValue) {
JsonElement childElement = getJsonElementForChild(fieldType, fieldValue);
private void addAsChildOfObject(Field f, ObjectTypePair fieldValuePair) {
JsonElement childElement = getJsonElementForChild(fieldValuePair);
addChildAsElement(f, childElement);
}
@ -149,17 +149,17 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
}
private void addAsArrayElement(Type elementType, Object elementValue) {
if (elementValue == null) {
private void addAsArrayElement(ObjectTypePair elementTypePair) {
if (elementTypePair.getObj() == null) {
root.getAsJsonArray().add(JsonNull.createJsonNull());
} else {
JsonElement childElement = getJsonElementForChild(elementType, elementValue);
JsonElement childElement = getJsonElementForChild(elementTypePair);
root.getAsJsonArray().add(childElement);
}
}
private JsonElement getJsonElementForChild(Type fieldType, Object fieldValue) {
ObjectNavigator on = factory.create(fieldValue, fieldType);
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
ObjectNavigator on = factory.create(fieldValueTypePair);
JsonSerializationVisitor childVisitor =
new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors);
on.accept(childVisitor);
@ -167,8 +167,10 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
@SuppressWarnings("unchecked")
public boolean visitUsingCustomHandler(Object obj, Type objType) {
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
try {
Object obj = objTypePair.getObj();
Type objType = objTypePair.getType();
JsonSerializer serializer = serializers.getHandlerFor(objType);
if (serializer == null && obj != null) {
serializer = serializers.getHandlerFor(obj.getClass());
@ -178,7 +180,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
if (obj == null) {
assignToRoot(JsonNull.createJsonNull());
} else {
assignToRoot(invokeCustomHandler(obj, objType, serializer));
assignToRoot(invokeCustomHandler(objTypePair, serializer));
}
return true;
}
@ -189,12 +191,12 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
@SuppressWarnings("unchecked")
private JsonElement invokeCustomHandler(Object obj, Type objType, JsonSerializer serializer) {
start(obj);
private JsonElement invokeCustomHandler(ObjectTypePair objTypePair, JsonSerializer serializer) {
start(objTypePair);
try {
return serializer.serialize(obj, objType, context);
return serializer.serialize(objTypePair.getObj(), objTypePair.getType(), context);
} finally {
end(obj);
end(objTypePair);
}
}
@ -211,7 +213,8 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
JsonSerializer serializer = serializers.getHandlerFor(actualTypeOfField);
if (serializer != null) {
JsonElement child = invokeCustomHandler(obj, actualTypeOfField, serializer);
ObjectTypePair objTypePair = new ObjectTypePair(obj, actualTypeOfField);
JsonElement child = invokeCustomHandler(objTypePair, serializer);
addChildAsElement(f, child);
return true;
}

View File

@ -25,8 +25,8 @@ import java.util.Stack;
*
* @author Joel Leitch
*/
final class MemoryRefStack<T> {
private final Stack<T> stack = new Stack<T>();
final class MemoryRefStack {
private final Stack<ObjectTypePair> stack = new Stack<ObjectTypePair>();
/**
* Adds a new element to the top of the stack.
@ -34,7 +34,7 @@ final class MemoryRefStack<T> {
* @param obj the object to add to the stack
* @return the object that was added
*/
public T push(T obj) {
public ObjectTypePair push(ObjectTypePair obj) {
Preconditions.checkNotNull(obj);
return stack.push(obj);
@ -46,7 +46,7 @@ final class MemoryRefStack<T> {
* @return the element being removed from the stack
* @throws java.util.EmptyStackException thrown if the stack is empty
*/
public T pop() {
public ObjectTypePair pop() {
return stack.pop();
}
@ -60,7 +60,7 @@ final class MemoryRefStack<T> {
* @return the item from the top of the stack
* @throws java.util.EmptyStackException thrown if the stack is empty
*/
public T peek() {
public ObjectTypePair peek() {
return stack.peek();
}
@ -71,13 +71,13 @@ final class MemoryRefStack<T> {
* @param obj the object to search for in the stack
* @return true if this object is already in the stack otherwise false
*/
public boolean contains(T obj) {
public boolean contains(ObjectTypePair obj) {
if (obj == null) {
return false;
}
for (T stackObject : stack) {
if (obj == stackObject) {
for (ObjectTypePair stackObject : stack) {
if (stackObject.getObj() == obj.getObj() && stackObject.getType().equals(obj.getType()) ) {
return true;
}
}

View File

@ -29,8 +29,8 @@ import java.lang.reflect.Type;
final class ObjectNavigator {
public interface Visitor {
public void start(Object node);
public void end(Object node);
public void start(ObjectTypePair node);
public void end(ObjectTypePair node);
/**
* This is called before the object navigator starts visiting the current object
@ -56,7 +56,7 @@ final class ObjectNavigator {
* This is called to visit an object using a custom handler
* @return true if a custom handler exists, false otherwise
*/
public boolean visitUsingCustomHandler(Object obj, Type objType);
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair);
/**
* This is called to visit a field of the current object using a custom handler
@ -72,20 +72,17 @@ final class ObjectNavigator {
}
private final ExclusionStrategy exclusionStrategy;
private final Object obj;
private final Type objType;
private final ObjectTypePair objTypePair;
/**
* @param obj The object being navigated
* @param objType The (fully genericized) type of the object being navigated
* @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(Object obj, Type objType, ExclusionStrategy exclusionStrategy) {
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
Preconditions.checkNotNull(exclusionStrategy);
this.obj = obj;
this.objType = objType;
this.objTypePair = objTypePair;
this.exclusionStrategy = exclusionStrategy;
}
@ -94,20 +91,21 @@ final class ObjectNavigator {
* If a field is null, it does not get visited.
*/
public void accept(Visitor visitor) {
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(obj, objType);
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
if (!visitedWithCustomHandler) {
Object obj = objTypePair.getObj();
Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
if (objectToVisit == null) {
return;
}
TypeInfo objTypeInfo = new TypeInfo(objType);
TypeInfo objTypeInfo = new TypeInfo(objTypePair.getType());
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
visitor.start(obj);
visitor.start(objTypePair);
try {
if (objTypeInfo.isArray()) {
visitor.visitArray(objectToVisit, objType);
visitor.visitArray(objectToVisit, objTypePair.getType());
} else if (objTypeInfo.getActualType() == Object.class
&& isPrimitiveOrString(objectToVisit)) {
// TODO(Joel): this is only used for deserialization of "primitves"
@ -128,7 +126,7 @@ final class ObjectNavigator {
}
}
} finally {
visitor.end(obj);
visitor.end(objTypePair);
}
}
}
@ -146,7 +144,7 @@ final class ObjectNavigator {
if (exclusionStrategy.shouldSkipField(f)) {
continue; // skip
} else {
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objType);
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.getType());
Type actualTypeOfField = fieldTypeInfo.getActualType();
boolean visitedWithCustomHandler =
visitor.visitFieldUsingCustomHandler(f, actualTypeOfField, obj);

View File

@ -16,8 +16,6 @@
package com.google.gson;
import java.lang.reflect.Type;
/**
* A factory class used to simplify {@link ObjectNavigator} creation.
* This object holds on to a reference of the {@link ExclusionStrategy}
@ -48,15 +46,13 @@ final class ObjectNavigatorFactory {
* Creates a new {@link ObjectNavigator} for this {@code srcObject},
* {@code type} pair.
*
* @param srcObject object to navigate
* @param type the "actual" type of this {@code srcObject}. NOTE: this can
* be a {@link java.lang.reflect.ParameterizedType} rather than a {@link Class}.
* @param objTypePair The object,type (fully genericized) being navigated
* @return a new instance of a {@link ObjectNavigator} ready to navigate the
* {@code srcObject} while taking into consideration the
* {@code type}.
*/
public ObjectNavigator create(Object srcObject, Type type) {
return new ObjectNavigator(srcObject, type, strategy);
public ObjectNavigator create(ObjectTypePair objTypePair) {
return new ObjectNavigator(objTypePair, strategy);
}
FieldNamingStrategy getFieldNamingPolicy() {

View File

@ -0,0 +1,47 @@
package com.google.gson;
import java.lang.reflect.Type;
final class ObjectTypePair {
private final Object obj;
private final Type type;
public ObjectTypePair(Object obj, Type type) {
this.obj = obj;
this.type = type;
}
public Object getObj() {
return obj;
}
public Type getType() {
return type;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((obj == null) ? 0 : obj.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ObjectTypePair other = (ObjectTypePair) obj;
if (this.obj == null) {
if (other.obj != null)
return false;
} else if (!this.obj.equals(other.obj))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
}

View File

@ -28,12 +28,12 @@ import java.util.EmptyStackException;
* @author Joel Leitch
*/
public class MemoryRefStackTest extends TestCase {
private MemoryRefStack<MockObject> stack;
private MemoryRefStack stack;
@Override
protected void setUp() throws Exception {
super.setUp();
stack = new MemoryRefStack<MockObject>();
stack = new MemoryRefStack();
}
public void testPeekEmptyStack() throws Exception {
@ -43,7 +43,7 @@ public class MemoryRefStackTest extends TestCase {
}
public void testPushPeekAndPop() throws Exception {
MockObject obj = new MockObject();
ObjectTypePair obj = new ObjectTypePair(this, getClass());
assertEquals(obj, stack.push(obj));
assertEquals(obj, stack.peek());
@ -51,7 +51,7 @@ public class MemoryRefStackTest extends TestCase {
}
public void testPopTooMany() throws Exception {
MockObject obj = new MockObject();
ObjectTypePair obj = new ObjectTypePair(this, getClass());
stack.push(obj);
assertEquals(obj, stack.pop());
@ -61,8 +61,8 @@ public class MemoryRefStackTest extends TestCase {
}
public void testContains() throws Exception {
MockObject objA = new MockObject();
MockObject objB = new MockObject();
ObjectTypePair objA = new ObjectTypePair(new MockObject(), MockObject.class);
ObjectTypePair objB = new ObjectTypePair(new MockObject(), MockObject.class);
assertEquals(objA, objB);
stack.push(objA);

View File

@ -32,6 +32,7 @@ public class InterfaceTest extends TestCase {
private Gson gson;
private TestObject obj;
@Override
protected void setUp() throws Exception {
super.setUp();
gson = new Gson();