Implement RPC custom serialization for Collections.singletonList()
Review at http://gwt-code-reviews.appspot.com/357801
Review by: jat@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7946 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/Long_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/Long_CustomFieldSerializer.java
index c8075cf..4b416b5 100644
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/Long_CustomFieldSerializer.java
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/lang/Long_CustomFieldSerializer.java
@@ -32,7 +32,7 @@
public static Long instantiate(SerializationStreamReader streamReader)
throws SerializationException {
- return new Long(streamReader.readLong());
+ return Long.valueOf(streamReader.readLong());
}
public static void serialize(SerializationStreamWriter streamWriter,
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/lang/Void_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/lang/Void_CustomFieldSerializer.java
index 240edf8..ad1cf52 100644
--- a/user/src/com/google/gwt/user/client/rpc/core/java/lang/Void_CustomFieldSerializer.java
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/lang/Void_CustomFieldSerializer.java
@@ -24,15 +24,18 @@
*/
public final class Void_CustomFieldSerializer {
+ @SuppressWarnings("unused")
public static void deserialize(SerializationStreamReader streamReader,
Void instance) {
}
+ @SuppressWarnings("unused")
public static Void instantiate(SerializationStreamReader streamReader)
throws SerializationException {
return null;
}
+ @SuppressWarnings("unused")
public static void serialize(SerializationStreamWriter streamWriter,
Void instance) throws SerializationException {
}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
index 56a77d3..4c24a79 100644
--- a/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
@@ -99,4 +99,27 @@
// Nothing to serialize -- instantiate always returns the same thing
}
}
+
+ /**
+ * Custom field serializer for {@link java.util.Collections$SingletonList}.
+ */
+ public static final class SingletonList_CustomFieldSerializer {
+
+ @SuppressWarnings({"unused", "unchecked"})
+ public static void deserialize(SerializationStreamReader streamReader,
+ List instance) throws SerializationException {
+ }
+
+ @SuppressWarnings({"unused", "unchecked"})
+ public static List instantiate(SerializationStreamReader streamReader)
+ throws SerializationException {
+ return java.util.Collections.singletonList(streamReader.readObject());
+ }
+
+ @SuppressWarnings({"unused", "unchecked"})
+ public static void serialize(SerializationStreamWriter streamWriter,
+ List instance) throws SerializationException {
+ streamWriter.writeObject(instance.get(0));
+ }
+ }
}
diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java
index 36c1031..bd2451a 100644
--- a/user/super/com/google/gwt/emul/java/util/Collections.java
+++ b/user/super/com/google/gwt/emul/java/util/Collections.java
@@ -1,12 +1,12 @@
/*
* Copyright 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
@@ -23,7 +23,7 @@
* docs]</a>
*/
public class Collections {
-
+
private static final class EmptyList extends AbstractList implements
RandomAccess, Serializable {
@Override
@@ -41,7 +41,7 @@
return 0;
}
}
-
+
private static final class EmptySet extends AbstractSet implements
Serializable {
@Override
@@ -110,6 +110,30 @@
}
}
+ private static final class SingletonList<E> extends AbstractList<E> implements Serializable {
+ private E element;
+
+ public SingletonList(E element) {
+ this.element = element;
+ }
+
+ public boolean contains(Object item) {
+ return Utility.equalsWithNullCheck(element, item);
+ }
+
+ public E get(int index) {
+ if (index == 0) {
+ return element;
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public int size() {
+ return 1;
+ }
+ }
+
/*
* TODO: make the unmodifiable collections serializable.
*/
@@ -172,7 +196,7 @@
public <E> E[] toArray(E[] a) {
return coll.toArray(a);
}
-
+
public String toString() {
return coll.toString();
}
@@ -335,7 +359,7 @@
/**
* Wrap an array of Map.Entries as UnmodifiableEntries.
- *
+ *
* @param array array to wrap
* @param size number of entries to wrap
*/
@@ -488,11 +512,11 @@
public K lastKey() {
return sortedMap.lastKey();
}
-
+
public SortedMap<K, V> subMap(K fromKey, K toKey) {
return new UnmodifiableSortedMap<K, V>(sortedMap.subMap(fromKey, toKey));
}
-
+
public SortedMap<K, V> tailMap(K fromKey) {
return new UnmodifiableSortedMap<K, V>(sortedMap.tailMap(fromKey));
}
@@ -511,7 +535,7 @@
public Comparator<? super E> comparator() {
return sortedSet.comparator();
}
-
+
@Override
public boolean equals(Object o) {
return sortedSet.equals(o);
@@ -520,7 +544,7 @@
public E first() {
return sortedSet.first();
}
-
+
@Override
public int hashCode() {
return sortedSet.hashCode();
@@ -623,13 +647,13 @@
/**
* Perform a binary search on a sorted List, using natural ordering.
- *
+ *
* <p>
* Note: The GWT implementation differs from the JDK implementation in that it
* does not do an iterator-based binary search for Lists that do not implement
* RandomAccess.
* </p>
- *
+ *
* @param sortedList object array to search
* @param key value to search for
* @return the index of an element with a matching value, or a negative number
@@ -653,7 +677,7 @@
// // FUTURE: implement
// return null;
// }
- //
+ //
// static <E> List<E> checkedList(List<E> list, Class<E> type) {
// // FUTURE: implement
// return null;
@@ -684,13 +708,13 @@
/**
* Perform a binary search on a sorted List, using a user-specified comparison
* function.
- *
+ *
* <p>
* Note: The GWT implementation differs from the JDK implementation in that it
* does not do an iterator-based binary search for Lists that do not implement
* RandomAccess.
* </p>
- *
+ *
* @param sortedList List to search
* @param key value to search for
* @param comparator comparision function, <code>null</code> indicates
@@ -911,9 +935,7 @@
// More efficient at runtime, but more code bloat to download
public static <T> List<T> singletonList(T o) {
- List<T> list = new ArrayList<T>(1);
- list.add(o);
- return unmodifiableList(list);
+ return new SingletonList<T>(o);
}
public static <K, V> Map<K, V> singletonMap(K key, V value) {
@@ -971,7 +993,7 @@
/**
* Replace contents of a list from an array.
- *
+ *
* @param <T> element type
* @param target list to replace contents from an array
* @param x an Object array which can contain only T instances
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
index eb718d3..da06099 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTest.java
@@ -22,6 +22,7 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
@@ -564,6 +565,23 @@
});
}
+ public void testSingletonList() {
+ CollectionsTestServiceAsync service = getServiceAsync();
+ delayTestFinishForRpc();
+ service.echoSingletonList(TestSetFactory.createSingletonList(),
+ new AsyncCallback<List<MarkerTypeSingleton>>() {
+ public void onFailure(Throwable caught) {
+ TestSetValidator.rethrowException(caught);
+ }
+
+ public void onSuccess(List<MarkerTypeSingleton> result) {
+ assertNotNull(result);
+ assertTrue(TestSetValidator.isValidSingletonList(result));
+ finishTest();
+ }
+ });
+ }
+
public void testSqlDateArray() {
CollectionsTestServiceAsync service = getServiceAsync();
final java.sql.Date[] expected = TestSetFactory.createSqlDateArray();
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
index 9c0b520..8ae7c93 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestService.java
@@ -22,6 +22,7 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
@@ -151,4 +152,8 @@
List<MarkerTypeArraysAsList> echoArraysAsList(
List<MarkerTypeArraysAsList> value)
throws CollectionsTestServiceException;
+
+ // For Collections.singletonList()
+ List<MarkerTypeSingleton> echoSingletonList(List<MarkerTypeSingleton> value)
+ throws CollectionsTestServiceException;
}
diff --git a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
index e6c5e38..10732bd 100644
--- a/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/CollectionsTestServiceAsync.java
@@ -22,6 +22,7 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
@@ -132,4 +133,8 @@
void echoArraysAsList(List<MarkerTypeArraysAsList> value,
AsyncCallback<List<MarkerTypeArraysAsList>> callback);
+
+ // For Collections.singletonList()
+ void echoSingletonList(List<MarkerTypeSingleton> value,
+ AsyncCallback<List<MarkerTypeSingleton>> callback);
}
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
index 7f749d9..9ae14ed 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetFactory.java
@@ -183,6 +183,16 @@
/**
* A single-use marker type to independently check type parameter exposure in
+ * singleton collections.
+ */
+ public static final class MarkerTypeSingleton extends MarkerBase {
+ MarkerTypeSingleton() {
+ super("singleton");
+ }
+ }
+
+ /**
+ * A single-use marker type to independently check type parameter exposure in
* various collections.
*/
public static final class MarkerTypeTreeMap extends MarkerBase {
@@ -550,6 +560,10 @@
new Short(Short.MAX_VALUE), new Short(Short.MIN_VALUE)};
}
+ public static List<MarkerTypeSingleton> createSingletonList() {
+ return java.util.Collections.singletonList(new MarkerTypeSingleton());
+ }
+
public static java.sql.Date[] createSqlDateArray() {
return new java.sql.Date[] {
new java.sql.Date(500L), new java.sql.Date(500000000L)};
diff --git a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
index 8bb3bd6..89f5c76 100644
--- a/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
+++ b/user/test/com/google/gwt/user/client/rpc/TestSetValidator.java
@@ -1,12 +1,12 @@
/*
* Copyright 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
@@ -16,6 +16,7 @@
package com.google.gwt.user.client.rpc;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeEmpty;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.SerializableDoublyLinkedNode;
@@ -534,6 +535,22 @@
return true;
}
+ public static boolean isValidSingletonList(List<MarkerTypeSingleton> list) {
+ if (list == null || list.size() != 1) {
+ return false;
+ }
+ Object value = list.get(0);
+ // Perform instanceof check in case RPC did the wrong thing
+ if (!(value instanceof MarkerTypeSingleton)) {
+ return false;
+ }
+ MarkerTypeSingleton singleton = (MarkerTypeSingleton) value;
+ if (!"singleton".equals(singleton.getValue())) {
+ return false;
+ }
+ return true;
+ }
+
public static boolean isValidTrivialCyclicGraph(
SerializableDoublyLinkedNode actual) {
if (actual == null) {
@@ -564,7 +581,7 @@
/**
* Wrap an exception in RuntimeException if necessary so it doesn't have to be
* listed in throws clauses.
- *
+ *
* @param caught exception to wrap
*/
public static void rethrowException(Throwable caught) {
diff --git a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
index 0b5ca20..f0ce23a 100644
--- a/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/CollectionsTestServiceImpl.java
@@ -25,6 +25,7 @@
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeHashSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeLinkedHashSet;
+import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeSingleton;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeMap;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeTreeSet;
import com.google.gwt.user.client.rpc.TestSetFactory.MarkerTypeVector;
@@ -429,4 +430,12 @@
return value;
}
+ public List<MarkerTypeSingleton> echoSingletonList(
+ List<MarkerTypeSingleton> value) throws CollectionsTestServiceException {
+ if (!TestSetValidator.isValidSingletonList(value)) {
+ throw new CollectionsTestServiceException();
+ }
+
+ return value;
+ }
}