Deserialization will no longer call the default constructor or InstanceCreator if the object being deserialized has a custom deserializer.

This commit is contained in:
Joel Leitch 2008-11-25 18:42:47 +00:00
parent 1e7f3ebe7a
commit 2effd57976
5 changed files with 138 additions and 24 deletions

View File

@ -70,8 +70,7 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
Object target = visitor.getTarget();
ObjectNavigator on = navigatorFactory.create(target, typeOfT);
ObjectNavigator on = navigatorFactory.create(null, typeOfT);
on.accept(visitor);
return visitor.getTarget();
}

View File

@ -52,7 +52,7 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
this.context = context;
}
T getTarget() {
public T getTarget() {
if (target == null) {
target = constructTarget();
}

View File

@ -44,6 +44,10 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
this.serializers = serializers;
this.context = context;
}
public Object getTarget() {
return null;
}
public void startVisitingObject(Object node) {
assignToRoot(new JsonObject());

View File

@ -59,6 +59,11 @@ final class ObjectNavigator {
* This is called to visit a field of the current object using a custom handler
*/
public boolean visitFieldUsingCustomHandler(Field f, Type actualTypeOfField, Object parent);
/**
* Retrieve the current target
*/
Object getTarget();
}
private final ExclusionStrategy exclusionStrategy;
@ -88,38 +93,39 @@ final class ObjectNavigator {
* If a field is null, it does not get visited.
*/
public void accept(Visitor visitor) {
if (obj == null) {
return;
}
TypeInfo objTypeInfo = new TypeInfo(objType);
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
if (ancestors.contains(obj)) {
throw new IllegalStateException("Circular reference found: " + obj);
}
ancestors.push(obj);
try {
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(obj, objType);
if (!visitedWithCustomHandler) {
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(obj, objType);
if (!visitedWithCustomHandler) {
Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
if (objectToVisit == null) {
return;
}
TypeInfo objTypeInfo = new TypeInfo(objType);
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return;
}
if (ancestors.contains(objectToVisit)) {
throw new IllegalStateException("Circular reference found: " + objectToVisit);
}
ancestors.push(objectToVisit);
try {
if (objTypeInfo.isArray()) {
visitor.visitArray(obj, objType);
visitor.visitArray(objectToVisit, objType);
} else {
visitor.startVisitingObject(obj);
visitor.startVisitingObject(objectToVisit);
// For all classes in the inheritance hierarchy (including the current class),
// visit all fields
for (Class<?> curr = objTypeInfo.getRawClass();
curr != null && !curr.equals(Object.class); curr = curr.getSuperclass()) {
if (!curr.isSynthetic()) {
navigateClassFields(obj, curr, visitor);
navigateClassFields(objectToVisit, curr, visitor);
}
}
}
} finally {
ancestors.pop();
}
} finally {
ancestors.pop();
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson.functional;
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import junit.framework.TestCase;
/**
* Functional Test exercising custom deserialization only. When test applies to both
* serialization and deserialization then add it to CustomTypeAdapterTest.
*
* @author Joel Leitch
*/
public class CustomDeserializerTest extends TestCase {
private static final String DEFAULT_VALUE = "test123";
private static final String SUFFIX = "blah";
private Gson gson;
@Override
protected void setUp() throws Exception {
super.setUp();
gson = new GsonBuilder().registerTypeAdapter(DataHolder.class, new DataHolderDeserializer()).create();
}
public void testDefaultConstructorNotCalledOnObject() throws Exception {
DataHolder data = new DataHolder(DEFAULT_VALUE);
String json = gson.toJson(data);
DataHolder actual = gson.fromJson(json, DataHolder.class);
assertEquals(DEFAULT_VALUE + SUFFIX, actual.getData());
}
public void testDefaultConstructorNotCalledOnField() throws Exception {
DataHolderWrapper dataWrapper = new DataHolderWrapper(new DataHolder(DEFAULT_VALUE));
String json = gson.toJson(dataWrapper);
DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class);
assertEquals(DEFAULT_VALUE + SUFFIX, actual.getWrappedData().getData());
}
private static class DataHolder {
private final String data;
public DataHolder() {
throw new IllegalStateException();
}
public DataHolder(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
private static class DataHolderWrapper {
private final DataHolder wrappedData;
public DataHolderWrapper() {
this(new DataHolder(DEFAULT_VALUE));
}
public DataHolderWrapper(DataHolder data) {
this.wrappedData = data;
}
public DataHolder getWrappedData() {
return wrappedData;
}
}
private static class DataHolderDeserializer implements JsonDeserializer<DataHolder> {
public DataHolder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObj = json.getAsJsonObject();
String dataString = jsonObj.get("data").getAsString();
return new DataHolder(dataString + SUFFIX);
}
}
}