Created an alpha package that holds experimental feature.
Added support for JsonPostDeserializer that allows you to invoke postDeserialize methods on an Gson deserialized object.
This commit is contained in:
parent
14f16e2d0c
commit
c25278b4d6
|
@ -33,8 +33,11 @@ import java.util.Map;
|
||||||
|
|
||||||
import com.google.gson.internal.ConstructorConstructor;
|
import com.google.gson.internal.ConstructorConstructor;
|
||||||
import com.google.gson.internal.Excluder;
|
import com.google.gson.internal.Excluder;
|
||||||
|
import com.google.gson.internal.ObjectConstructor;
|
||||||
import com.google.gson.internal.Primitives;
|
import com.google.gson.internal.Primitives;
|
||||||
import com.google.gson.internal.Streams;
|
import com.google.gson.internal.Streams;
|
||||||
|
import com.google.gson.internal.alpha.Intercept;
|
||||||
|
import com.google.gson.internal.alpha.JsonPostDeserializer;
|
||||||
import com.google.gson.internal.bind.ArrayTypeAdapter;
|
import com.google.gson.internal.bind.ArrayTypeAdapter;
|
||||||
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
|
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
|
||||||
import com.google.gson.internal.bind.DateTypeAdapter;
|
import com.google.gson.internal.bind.DateTypeAdapter;
|
||||||
|
@ -791,8 +794,11 @@ public final class Gson {
|
||||||
try {
|
try {
|
||||||
reader.peek();
|
reader.peek();
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getAdapter(TypeToken.get(typeOfT));
|
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
|
||||||
return typeAdapter.read(reader);
|
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getAdapter(typeToken);
|
||||||
|
T object = typeAdapter.read(reader);
|
||||||
|
invokeInterceptorIfNeeded(object, typeToken);
|
||||||
|
return object;
|
||||||
} catch (EOFException e) {
|
} catch (EOFException e) {
|
||||||
/*
|
/*
|
||||||
* For compatibility with JSON 1.5 and earlier, we return null for empty
|
* For compatibility with JSON 1.5 and earlier, we return null for empty
|
||||||
|
@ -884,6 +890,20 @@ public final class Gson {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
private <T> void invokeInterceptorIfNeeded(T object, TypeToken<T> type) {
|
||||||
|
Class<? super T> clazz = type.getRawType();
|
||||||
|
Intercept interceptor = clazz.getAnnotation(Intercept.class);
|
||||||
|
if (interceptor == null) return;
|
||||||
|
// TODO: We don't need to construct an instance of postDeserializer every time. we can
|
||||||
|
// create it once and cache it.
|
||||||
|
Class<? extends JsonPostDeserializer> postDeserializerClass = interceptor.postDeserialize();
|
||||||
|
ObjectConstructor<? extends JsonPostDeserializer> objectConstructor =
|
||||||
|
constructorConstructor.get(TypeToken.get(postDeserializerClass));
|
||||||
|
JsonPostDeserializer<T> postDeserializer = objectConstructor.construct();
|
||||||
|
postDeserializer.postDeserialize(object);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder("{")
|
StringBuilder sb = new StringBuilder("{")
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.internal.alpha;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this annotation to indicate various interceptors for class instances after
|
||||||
|
* they have been processed by Gson. For example, you can use it to validate an instance
|
||||||
|
* after it has been deserialized from Json.
|
||||||
|
* Here is an example of how this annotation is used:
|
||||||
|
* <p>Here is an example of how this annotation is used:
|
||||||
|
* <p><pre>
|
||||||
|
* @Intercept(postDeserialize=UserValidator.class)
|
||||||
|
* public class User {
|
||||||
|
* String name;
|
||||||
|
* String password;
|
||||||
|
* String emailAddress;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public class UserValidator implements JsonPostDeserializer<User> {
|
||||||
|
* public void postDeserialize(User user) {
|
||||||
|
* // Do some checks on user
|
||||||
|
* if (user.name == null || user.password == null) {
|
||||||
|
* throw new JsonParseException("name and password are required fields.");
|
||||||
|
* }
|
||||||
|
* if (user.emailAddress == null) {
|
||||||
|
* emailAddress = "unknown"; // assign a default value.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre></p>
|
||||||
|
*
|
||||||
|
* @author Inderjeet Singh
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface Intercept {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the class that provides the methods that should be invoked after an instance
|
||||||
|
* has been deserialized.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public Class<? extends JsonPostDeserializer> postDeserialize();
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.internal.alpha;
|
||||||
|
|
||||||
|
import com.google.gson.InstanceCreator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is implemented by a class that wishes to inspect or modify an object
|
||||||
|
* after it has been deserialized. You must define a no-args constructor or register an
|
||||||
|
* {@link InstanceCreator} for such a class.
|
||||||
|
*
|
||||||
|
* @author Inderjeet Singh
|
||||||
|
*/
|
||||||
|
public interface JsonPostDeserializer<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by Gson after the object has been deserialized from Json.
|
||||||
|
*/
|
||||||
|
public void postDeserialize(T object);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* This package provides experimental Gson features that are very likely to change from
|
||||||
|
* release to release. Backwards compatibility will almost certainly be broken in a future
|
||||||
|
* release by either changing the package name (when the feature moves to main Gson) or when
|
||||||
|
* we decide that the feature isn't worth adding.
|
||||||
|
*
|
||||||
|
* @author Inderjeet Singh, Joel Leitch, Jesse Wilson
|
||||||
|
*/
|
||||||
|
package com.google.gson.internal.alpha;
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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 junit.framework.TestCase;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.internal.alpha.Intercept;
|
||||||
|
import com.google.gson.internal.alpha.JsonPostDeserializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link Intercept} and {@link JsonPostDeserializer}.
|
||||||
|
*
|
||||||
|
* @author Inderjeet Singh
|
||||||
|
*/
|
||||||
|
public final class InterceptorTest extends TestCase {
|
||||||
|
|
||||||
|
private Gson gson;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
this.gson = new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPostDeserialize() {
|
||||||
|
MyObject target = gson.fromJson("{}", MyObject.class);
|
||||||
|
assertEquals(MyObject.DEFAULT_VALUE, target.value);
|
||||||
|
assertEquals(MyObject.DEFAULT_MESSAGE, target.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Intercept(postDeserialize = MyObjectInterceptor.class)
|
||||||
|
private static final class MyObject {
|
||||||
|
static final int DEFAULT_VALUE = 10;
|
||||||
|
static final String DEFAULT_MESSAGE = "hello";
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
String message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MyObjectInterceptor implements JsonPostDeserializer<MyObject> {
|
||||||
|
public void postDeserialize(MyObject o) {
|
||||||
|
if (o.value == 0) {
|
||||||
|
o.value = MyObject.DEFAULT_VALUE;
|
||||||
|
}
|
||||||
|
if (o.message == null) {
|
||||||
|
o.message = MyObject.DEFAULT_MESSAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user