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; + } }