Revised equals and hashcode of ObjectTypePair to ensure reference equality of object instead of value equality. Improved JavaDocs for various 1.4 API methods.

This commit is contained in:
Inderjeet Singh 2009-10-05 18:17:52 +00:00
parent 2716d96516
commit ff74224815
9 changed files with 90 additions and 49 deletions

View File

@ -64,7 +64,10 @@ public enum FieldNamingPolicy {
* <li>aStringField ---> a-string-field</li> * <li>aStringField ---> a-string-field</li>
* <li>aURL ---> a-u-r-l</li> * <li>aURL ---> a-u-r-l</li>
* </ul> * </ul>
* * Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
* expressions. This requires that a field named with dashes is always accessed as a quoted
* property like {@code myobject['my-field']}. Accessing it as an object field
* {@code myobject.my-field} will result in an unintended javascript expression.
* @since 1.4 * @since 1.4
*/ */
LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-")); LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-"));

View File

@ -187,13 +187,12 @@ public final class Gson {
/** /**
* This method serializes the specified object into its equivalent representation as a tree of * This method serializes the specified object into its equivalent representation as a tree of
* {JsonElement}s. This method should be used when the specified object is not a generic type. * {@link JsonElement}s. This method should be used when the specified object is not a generic
* This method uses {@link Class#getClass()} to get the type for the specified object, but the * type. This method uses {@link Class#getClass()} to get the type for the specified object, but
* {@code getClass()} loses the generic type information because of the Type Erasure feature * the {@code getClass()} loses the generic type information because of the Type Erasure feature
* of Java. Note that this method works fine if the any of the object fields are of generic type, * of Java. Note that this method works fine if the any of the object fields are of generic type,
* just the object itself should not be of a generic type. If the object is of generic type, use * just the object itself should not be of a generic type. If the object is of generic type, use
* {@link #toJson(Object, Type)} instead. If you want to write out the object to a * {@link #toJsonTree(Object, Type)} instead.
* {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
* *
* @param src the object for which Json representation is to be created setting for Gson * @param src the object for which Json representation is to be created setting for Gson
* @return Json representation of {@code src}. * @return Json representation of {@code src}.
@ -209,9 +208,8 @@ public final class Gson {
/** /**
* This method serializes the specified object, including those of generic types, into its * This method serializes the specified object, including those of generic types, into its
* equivalent representation as a tree of {@link JsonElement}s. This method must be used if the * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the
* specified object is a generic type. For non-generic objects, use {@link #toJson(Object)} * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)}
* instead. If you want to write out the object to a {@link Appendable}, * instead.
* use {@link #toJson(Object, Type, Appendable)} instead.
* *
* @param src the object for which JSON representation is to be created * @param src the object for which JSON representation is to be created
* @param typeOfSrc The specific genericized type of src. You can obtain * @param typeOfSrc The specific genericized type of src. You can obtain
@ -321,7 +319,7 @@ public final class Gson {
/** /**
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation. * Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
* *
* @param jsonElement root of the tree of {@link JsonElement}s * @param jsonElement root of a tree of {@link JsonElement}s
* @return JSON String representation of the tree * @return JSON String representation of the tree
* @since 1.4 * @since 1.4
*/ */
@ -332,9 +330,9 @@ public final class Gson {
} }
/** /**
* Writes out the equivalent JSON for the tree of {@link JsonElement}s. * Writes out the equivalent JSON for a tree of {@link JsonElement}s.
* *
* @param jsonElement root of the tree of {@link JsonElement}s * @param jsonElement root of a tree of {@link JsonElement}s
* @param writer Writer to which the Json representation needs to be written * @param writer Writer to which the Json representation needs to be written
* @since 1.4 * @since 1.4
*/ */

View File

@ -150,7 +150,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
} }
private void addAsArrayElement(ObjectTypePair elementTypePair) { private void addAsArrayElement(ObjectTypePair elementTypePair) {
if (elementTypePair.getObj() == null) { if (elementTypePair.getObject() == null) {
root.getAsJsonArray().add(JsonNull.createJsonNull()); root.getAsJsonArray().add(JsonNull.createJsonNull());
} else { } else {
JsonElement childElement = getJsonElementForChild(elementTypePair); JsonElement childElement = getJsonElementForChild(elementTypePair);
@ -169,7 +169,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) { public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
try { try {
Object obj = objTypePair.getObj(); Object obj = objTypePair.getObject();
Type objType = objTypePair.getType(); Type objType = objTypePair.getType();
JsonSerializer serializer = serializers.getHandlerFor(objType); JsonSerializer serializer = serializers.getHandlerFor(objType);
if (serializer == null && obj != null) { if (serializer == null && obj != null) {
@ -194,7 +194,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
private JsonElement invokeCustomHandler(ObjectTypePair objTypePair, JsonSerializer serializer) { private JsonElement invokeCustomHandler(ObjectTypePair objTypePair, JsonSerializer serializer) {
start(objTypePair); start(objTypePair);
try { try {
return serializer.serialize(objTypePair.getObj(), objTypePair.getType(), context); return serializer.serialize(objTypePair.getObject(), objTypePair.getType(), context);
} finally { } finally {
end(objTypePair); end(objTypePair);
} }

View File

@ -25,14 +25,12 @@ import java.util.NoSuchElementException;
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously. * asynchronously.
* *
* <p>This class is thread-compatible. For some more literature on these definitions, refer to * <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
* Effective Java. * properly use this class across multiple threads, you will need to add some external
* * synchronization. For example:
* <p>To properly use this class across multiple thread, you will need to add some external
* synchronization to your classes/thread to get this to work properly. For example:
* *
* <pre> * <pre>
* JsonStreamParser parser = new JsonStreamParser("blah blah blah"); * JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'");
* JsonElement element; * JsonElement element;
* synchronized (someCommonObject) { * synchronized (someCommonObject) {
* if (parser.hasNext()) { * if (parser.hasNext()) {
@ -104,6 +102,11 @@ public final class JsonStreamParser implements Iterator<JsonElement> {
} }
} }
/**
* Returns true if a {@link JsonElement} is available on the input for consumption
* @return true if a {@link JsonElement} is available on the input, false otherwise
* @since 1.4
*/
public boolean hasNext() { public boolean hasNext() {
synchronized (lock) { synchronized (lock) {
try { try {
@ -116,6 +119,11 @@ public final class JsonStreamParser implements Iterator<JsonElement> {
} }
} }
/**
* This optional {@link Iterator} method is not relevant for stream parsing and hence is not
* implemented.
* @since 1.4
*/
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -77,7 +77,8 @@ final class MemoryRefStack {
} }
for (ObjectTypePair stackObject : stack) { for (ObjectTypePair stackObject : stack) {
if (stackObject.getObj() == obj.getObj() && stackObject.getType().equals(obj.getType()) ) { if (stackObject.getObject() == obj.getObject()
&& stackObject.getType().equals(obj.getType()) ) {
return true; return true;
} }
} }

View File

@ -93,7 +93,7 @@ final class ObjectNavigator {
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair); boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
if (!visitedWithCustomHandler) { if (!visitedWithCustomHandler) {
Object obj = objTypePair.getObj(); Object obj = objTypePair.getObject();
Object objectToVisit = (obj == null) ? visitor.getTarget() : obj; Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
if (objectToVisit == null) { if (objectToVisit == null) {
return; return;

View File

@ -1,47 +1,79 @@
/*
* Copyright (C) 2009 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; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
final class ObjectTypePair { /**
* A holder class for an object and its type
*
* @author Inderjeet Singh
*/
final class ObjectTypePair {
private static final int PRIME = 31;
private final Object obj; private final Object obj;
private final Type type; private final Type type;
public ObjectTypePair(Object obj, Type type) { public ObjectTypePair(Object obj, Type type) {
this.obj = obj; this.obj = obj;
this.type = type; this.type = type;
} }
public Object getObj() {
public Object getObject() {
return obj; return obj;
} }
public Type getType() { public Type getType() {
return type; return type;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; // Not using type.hashCode() since I am not sure if the subclasses of type reimplement
int result = 1; // hashCode() to be equal for equal types
result = prime * result + ((obj == null) ? 0 : obj.hashCode()); return ((obj == null) ? PRIME : obj.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj) {
return true; return true;
if (obj == null) }
if (obj == null) {
return false; return false;
if (getClass() != obj.getClass()) }
if (getClass() != obj.getClass()) {
return false; return false;
}
ObjectTypePair other = (ObjectTypePair) obj; ObjectTypePair other = (ObjectTypePair) obj;
if (this.obj == null) { if (this.obj == null) {
if (other.obj != null) if (other.obj != null) {
return false; return false;
} else if (!this.obj.equals(other.obj)) }
} else if (this.obj != other.obj) { // Checking for reference equality
return false; return false;
}
if (type == null) { if (type == null) {
if (other.type != null) if (other.type != null) {
return false; return false;
} else if (!type.equals(other.type)) }
} else if (!type.equals(other.type)) {
return false; return false;
}
return true; return true;
} }
} }

View File

@ -62,17 +62,17 @@ import java.lang.annotation.Target;
public @interface Expose { public @interface Expose {
/** /**
* If true, the field marked with this annotation is written out in the JSON while serializing. * If {@code true}, the field marked with this annotation is written out in the JSON while
* If false, the field marked with this annotation is skipped from the serialized output. * serializing. If {@code false}, the field marked with this annotation is skipped from the
* Defaults to true. * serialized output. Defaults to {@code true}.
* @since 1.4 * @since 1.4
*/ */
public boolean serialize() default true; public boolean serialize() default true;
/** /**
* If true, the field marked with this annotation is deserialized from the JSON. * If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If false, the field marked with this annotation is skipped during deserialization. * If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to true. * Defaults to {@code true}.
* @since 1.4 * @since 1.4
*/ */
public boolean deserialize() default true; public boolean deserialize() default true;

View File

@ -61,13 +61,12 @@ public class MemoryRefStackTest extends TestCase {
} }
public void testContains() throws Exception { public void testContains() throws Exception {
ObjectTypePair objA = new ObjectTypePair(new MockObject(), MockObject.class); MockObject objA = new MockObject();
ObjectTypePair objB = new ObjectTypePair(new MockObject(), MockObject.class); MockObject objB = new MockObject();
assertEquals(objA, objB); assertEquals(objA, objB);
stack.push(new ObjectTypePair(objA, MockObject.class));
stack.push(objA); assertTrue(stack.contains(new ObjectTypePair(objA, MockObject.class)));
assertFalse(stack.contains(objB)); assertFalse(stack.contains(new ObjectTypePair(objB, MockObject.class)));
assertTrue(stack.contains(objA));
} }
private static class MockObject { private static class MockObject {