/* * Copyright 2011 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.gwt.user.client.rpc; import com.google.gwt.event.shared.UmbrellaException; import java.io.Serializable; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; /** * Creates test collections. */ public class TestSetFactory { /** * Base type for single-use marker types to independently check type parameter * exposure in various collections. */ public static class MarkerBase implements IsSerializable { private String value; public MarkerBase(String value) { this.value = value; } @Override public boolean equals(Object obj) { if (obj instanceof MarkerBase && obj.getClass() == this.getClass()) { MarkerBase other = (MarkerBase) obj; return value == other.value || (value != null && value.equals(other.value)); } return false; } public String getValue() { return value; } @Override public int hashCode() { return value.hashCode(); } @Override public String toString() { return value; } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeArrayList extends MarkerBase { public MarkerTypeArrayList(String value) { super(value); } MarkerTypeArrayList() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeArraysAsList extends MarkerBase { public MarkerTypeArraysAsList(String value) { super(value); } MarkerTypeArraysAsList() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various empty collections. */ public static final class MarkerTypeEmptyKey extends MarkerBase { MarkerTypeEmptyKey() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various empty collections. */ public static final class MarkerTypeEmptyList extends MarkerBase { MarkerTypeEmptyList() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various empty collections. */ public static final class MarkerTypeEmptySet extends MarkerBase { MarkerTypeEmptySet() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various empty collections. */ public static final class MarkerTypeEmptyValue extends MarkerBase { MarkerTypeEmptyValue() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static enum MarkerTypeEnum { A, B, C; } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeHashMapKey extends MarkerBase { public MarkerTypeHashMapKey(String value) { super(value); } MarkerTypeHashMapKey() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeHashMapValue extends MarkerBase { public MarkerTypeHashMapValue(String value) { super(value); } MarkerTypeHashMapValue() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeHashSet extends MarkerBase { public MarkerTypeHashSet(String value) { super(value); } MarkerTypeHashSet() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeIdentityHashMapKey extends MarkerBase { public MarkerTypeIdentityHashMapKey(String value) { super(value); } MarkerTypeIdentityHashMapKey() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeIdentityHashMapValue extends MarkerBase { public MarkerTypeIdentityHashMapValue(String value) { super(value); } MarkerTypeIdentityHashMapValue() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeLinkedHashMapKey extends MarkerBase { public MarkerTypeLinkedHashMapKey(String value) { super(value); } MarkerTypeLinkedHashMapKey() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeLinkedHashMapValue extends MarkerBase { public MarkerTypeLinkedHashMapValue(String value) { super(value); } MarkerTypeLinkedHashMapValue() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeLinkedHashSet extends MarkerBase { public MarkerTypeLinkedHashSet(String value) { super(value); } MarkerTypeLinkedHashSet() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeLinkedList extends MarkerBase { public MarkerTypeLinkedList(String value) { super(value); } MarkerTypeLinkedList() { super(null); } } /** * 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 { public MarkerTypeTreeMap(String value) { super(value); } MarkerTypeTreeMap() { super(null); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeTreeSet extends MarkerBase implements Comparable<MarkerTypeTreeSet> { public MarkerTypeTreeSet(String value) { super(value); } MarkerTypeTreeSet() { super(null); } // if getValue() returns null, a null-pointer expection will be thrown, // which is the intended effect public int compareTo(MarkerTypeTreeSet arg0) { return getValue().compareTo(arg0.getValue()); } } /** * A single-use marker type to independently check type parameter exposure in * various collections. */ public static final class MarkerTypeVector extends MarkerBase { public MarkerTypeVector(String value) { super(value); } MarkerTypeVector() { super(null); } } /** * Class to test serialization of cycles in the object graph. */ public static class SerializableDoublyLinkedNode implements IsSerializable { protected String data; protected SerializableDoublyLinkedNode leftChild; protected SerializableDoublyLinkedNode rightChild; public String getData() { return data; } public SerializableDoublyLinkedNode getLeftChild() { return leftChild; } public SerializableDoublyLinkedNode getRightChild() { return rightChild; } public void setData(String data) { this.data = data; } public void setLeftChild(SerializableDoublyLinkedNode leftChild) { this.leftChild = leftChild; } public void setRightChild(SerializableDoublyLinkedNode rightChild) { this.rightChild = rightChild; } } /** * Test reference cycles where the reference graph passes through a * CustomFieldSerializer. */ public static final class SerializableGraphWithCFS implements Serializable { private ArrayList<SerializableGraphWithCFS> array; private SerializableGraphWithCFS parent; public SerializableGraphWithCFS() { array = new ArrayList<SerializableGraphWithCFS>(); array.add(new SerializableGraphWithCFS(this)); } public SerializableGraphWithCFS(SerializableGraphWithCFS parent) { this.parent = parent; } public ArrayList<SerializableGraphWithCFS> getArray() { return array; } public SerializableGraphWithCFS getParent() { return parent; } } /** * Tests that classes with a private no-arg constructor can be serialized. */ public static class SerializablePrivateNoArg implements IsSerializable { private int value; public SerializablePrivateNoArg(int value) { this(); this.value = value; } private SerializablePrivateNoArg() { } public int getValue() { return value; } } /** * Serializable class used to test arrays that are referenced more than once. */ public static class SerializableWithTwoArrays implements IsSerializable { String[] one; String[] two; } /** * A non-serializable class for testing. */ public static class UnserializableNode { } /** * A custom sorter for testing: it sorts in reverse order. * * @param <T> The type to be sorted. */ public static class ReverseSorter<T extends Comparable<T>> implements Comparator<T>, IsSerializable { // for gwt-serialization public ReverseSorter() { } public int compare(T a, T b) { // Explicit null check to match JRE specs if (a == null || b == null) { throw new NullPointerException(); } return b.compareTo(a); } @Override public boolean equals(Object ob) { if (!(ob instanceof ReverseSorter)) { return false; } return true; } @Override public int hashCode() { return 0; } } public static ArrayList<MarkerTypeArrayList> createArrayList() { ArrayList<MarkerTypeArrayList> list = new ArrayList<MarkerTypeArrayList>(); list.add(new MarkerTypeArrayList("foo")); list.add(new MarkerTypeArrayList("bar")); list.add(new MarkerTypeArrayList("baz")); list.add(new MarkerTypeArrayList("bal")); list.add(new MarkerTypeArrayList("w00t")); return list; } public static ArrayList<Void> createArrayListVoid() { ArrayList<Void> list = new ArrayList<Void>(); list.add(null); list.add(null); return list; } public static List<MarkerTypeArraysAsList> createArraysAsList() { return Arrays.asList(new MarkerTypeArraysAsList("foo"), new MarkerTypeArraysAsList("bar"), new MarkerTypeArraysAsList("baz"), new MarkerTypeArraysAsList("bal"), new MarkerTypeArraysAsList("w00t")); } public static Boolean[] createBooleanArray() { return new Boolean[]{ Boolean.valueOf(true), Boolean.valueOf(false), Boolean.valueOf(true), Boolean.valueOf(false)}; } public static Byte[] createByteArray() { return new Byte[]{ new Byte(Byte.MAX_VALUE), new Byte(Byte.MIN_VALUE), new Byte(Byte.MAX_VALUE), new Byte(Byte.MIN_VALUE)}; } public static Character[] createCharArray() { return new Character[]{ new Character(Character.MAX_VALUE), new Character(Character.MIN_VALUE), new Character(Character.MAX_VALUE), new Character(Character.MIN_VALUE)}; } public static SerializableGraphWithCFS createComplexCyclicGraphWithCFS() { return new SerializableGraphWithCFS(); } @SuppressWarnings("deprecation") public static Date[] createDateArray() { return new Date[]{new Date(1992 - 1900, 9, 18), new Date(1997 - 1900, 6, 6)}; } public static Double[] createDoubleArray() { return new Double[]{ new Double(Double.MAX_VALUE), new Double(Double.MIN_VALUE), new Double(Double.MAX_VALUE), new Double(Double.MIN_VALUE)}; } public static List<MarkerTypeEmptyList> createEmptyList() { return java.util.Collections.emptyList(); } public static Map<MarkerTypeEmptyKey, MarkerTypeEmptyValue> createEmptyMap() { return java.util.Collections.emptyMap(); } public static Set<MarkerTypeEmptySet> createEmptySet() { return java.util.Collections.emptySet(); } public static Enum<?>[] createEnumArray() { return new Enum<?>[]{MarkerTypeEnum.A, MarkerTypeEnum.B, MarkerTypeEnum.C, MarkerTypeEnum.A}; } public static Float[] createFloatArray() { return new Float[]{ new Float(Float.MAX_VALUE), new Float(Float.MIN_VALUE), new Float(Float.MAX_VALUE), new Float(Float.MIN_VALUE)}; } public static HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> createHashMap() { HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue> map = new HashMap<MarkerTypeHashMapKey, MarkerTypeHashMapValue>(); map.put(new MarkerTypeHashMapKey("foo"), new MarkerTypeHashMapValue("foo")); map.put(new MarkerTypeHashMapKey("bar"), new MarkerTypeHashMapValue("bar")); map.put(new MarkerTypeHashMapKey("baz"), new MarkerTypeHashMapValue("baz")); map.put(new MarkerTypeHashMapKey("bal"), new MarkerTypeHashMapValue("bal")); map.put(new MarkerTypeHashMapKey("w00t"), new MarkerTypeHashMapValue("w00t")); return map; } public static HashSet<MarkerTypeHashSet> createHashSet() { HashSet<MarkerTypeHashSet> set = new HashSet<MarkerTypeHashSet>(); set.add(new MarkerTypeHashSet("foo")); set.add(new MarkerTypeHashSet("bar")); set.add(new MarkerTypeHashSet("baz")); set.add(new MarkerTypeHashSet("bal")); set.add(new MarkerTypeHashSet("w00t")); return set; } public static IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> createIdentityHashMapEnumKey() { IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue> map = new IdentityHashMap<MarkerTypeEnum, MarkerTypeIdentityHashMapValue>(); /* * An Enum hash map lets us check that references to Enums remain constant * across RPC send-receive cycles. */ map.put(MarkerTypeEnum.A, new MarkerTypeIdentityHashMapValue("A")); map.put(MarkerTypeEnum.B, new MarkerTypeIdentityHashMapValue("B")); map.put(MarkerTypeEnum.C, new MarkerTypeIdentityHashMapValue("C")); return map; } public static IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> createIdentityHashMap() { IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue> map = new IdentityHashMap<MarkerTypeIdentityHashMapKey, MarkerTypeIdentityHashMapValue>(); /* * The two distinct instances of the Integer 1 will remain distinct in the * IdentityHashMap because they are not reference equal. They should * serialize such that the two distinct entries remain. */ map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo1")); map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo2")); map.put(new MarkerTypeIdentityHashMapKey("foo"), new MarkerTypeIdentityHashMapValue("foo3")); map.put(new MarkerTypeIdentityHashMapKey("bar"), new MarkerTypeIdentityHashMapValue("bar")); map.put(new MarkerTypeIdentityHashMapKey("baz"), new MarkerTypeIdentityHashMapValue("baz")); map.put(new MarkerTypeIdentityHashMapKey("bal"), new MarkerTypeIdentityHashMapValue("bal")); return map; } public static Integer[] createIntegerArray() { return new Integer[]{ new Integer(Integer.MAX_VALUE), new Integer(Integer.MIN_VALUE), new Integer(Integer.MAX_VALUE), new Integer(Integer.MIN_VALUE)}; } public static LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>createLinkedHashMap() { LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> map = new LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>(); map.put(new MarkerTypeLinkedHashMapKey("foo"), new MarkerTypeLinkedHashMapValue("foo")); map.put(new MarkerTypeLinkedHashMapKey("bar"), new MarkerTypeLinkedHashMapValue("bar")); map.put(new MarkerTypeLinkedHashMapKey("baz"), new MarkerTypeLinkedHashMapValue("baz")); map.put(new MarkerTypeLinkedHashMapKey("bal"), new MarkerTypeLinkedHashMapValue("bal")); map.put(new MarkerTypeLinkedHashMapKey("w00t"), new MarkerTypeLinkedHashMapValue("w00t")); return map; } public static LinkedHashSet<MarkerTypeLinkedHashSet> createLinkedHashSet() { LinkedHashSet<MarkerTypeLinkedHashSet> set = new LinkedHashSet<MarkerTypeLinkedHashSet>(); set.add(new MarkerTypeLinkedHashSet("foo")); set.add(new MarkerTypeLinkedHashSet("bar")); set.add(new MarkerTypeLinkedHashSet("baz")); set.add(new MarkerTypeLinkedHashSet("bal")); set.add(new MarkerTypeLinkedHashSet("w00t")); return set; } public static LinkedList<MarkerTypeLinkedList> createLinkedList() { LinkedList<MarkerTypeLinkedList> list = new LinkedList<MarkerTypeLinkedList>(); list.add(new MarkerTypeLinkedList("foo")); list.add(new MarkerTypeLinkedList("bar")); list.add(new MarkerTypeLinkedList("baz")); list.add(new MarkerTypeLinkedList("bal")); list.add(new MarkerTypeLinkedList("w00t")); return list; } public static Long[] createLongArray() { long a = 16123432898849345L; long b = 78234569989880099L; long c = -64289238928934943L; // Create values that are not compile-time constants for (int i = 0; i < 10; i++) { a ^= b; b ^= c; c ^= a; } return new Long[]{ new Long(Long.MAX_VALUE), new Long(Long.MIN_VALUE), new Long(Long.MAX_VALUE), new Long(Long.MIN_VALUE), new Long(a), new Long(b), new Long(c)}; } public static LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> createLRULinkedHashMap() { LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue> map = new LinkedHashMap<MarkerTypeLinkedHashMapKey, MarkerTypeLinkedHashMapValue>(100, 1.0f, true); map.put(new MarkerTypeLinkedHashMapKey("foo"), new MarkerTypeLinkedHashMapValue("foo")); map.put(new MarkerTypeLinkedHashMapKey("bar"), new MarkerTypeLinkedHashMapValue("bar")); map.put(new MarkerTypeLinkedHashMapKey("baz"), new MarkerTypeLinkedHashMapValue("baz")); map.put(new MarkerTypeLinkedHashMapKey("bal"), new MarkerTypeLinkedHashMapValue("bal")); map.put(new MarkerTypeLinkedHashMapKey("w00t"), new MarkerTypeLinkedHashMapValue("w00t")); return map; } public static boolean[] createPrimitiveBooleanArray() { return new boolean[]{true, true, false, false, true, false}; } public static byte[] createPrimitiveByteArray() { return new byte[]{Byte.MAX_VALUE, Byte.MIN_VALUE, Byte.MAX_VALUE, Byte.MIN_VALUE}; } public static char[] createPrimitiveCharArray() { return new char[]{ Character.MAX_VALUE, Character.MIN_VALUE, Character.MAX_VALUE, Character.MIN_VALUE}; } public static double[] createPrimitiveDoubleArray() { return new double[]{Double.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE, Double.MIN_VALUE}; } public static float[] createPrimitiveFloatArray() { return new float[]{Float.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Float.MIN_VALUE}; } public static int[] createPrimitiveIntegerArray() { return new int[]{Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE}; } public static long[] createPrimitiveLongArray() { long a = 16123432898849345L; long b = 78234569989880099L; long c = -64289238928934943L; // Create values that are not compile-time constants for (int i = 0; i < 10; i++) { a ^= b; b ^= c; c ^= a; } return new long[]{Long.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE, Long.MIN_VALUE, a, b, c}; } public static short[] createPrimitiveShortArray() { return new short[]{Short.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Short.MIN_VALUE}; } public static SerializablePrivateNoArg createPrivateNoArg() { return new SerializablePrivateNoArg(1); } public static Short[] createShortArray() { return new Short[]{ new Short(Short.MAX_VALUE), new Short(Short.MIN_VALUE), 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)}; } public static Time[] createSqlTimeArray() { return new Time[]{new Time(500L), new Time(5000000L)}; } public static Timestamp[] createSqlTimestampArray() { return new Timestamp[]{new Timestamp(500L), new Timestamp(5000000L)}; } /* * Check names that collide with JS properties inherited from Object.prototype * to make sure they are handled properly. */ public static String[] createStringArray() { return new String[]{ null, "", "one", "two", "toString", "watch", "prototype", "eval", "valueOf", "constructor", "__proto__"}; } public static TreeMap<String, MarkerTypeTreeMap> createTreeMap(boolean defaultComparator) { TreeMap<String, MarkerTypeTreeMap> map; if (defaultComparator) { map = new TreeMap<String, MarkerTypeTreeMap>(); } else { map = new TreeMap<String, MarkerTypeTreeMap>(new ReverseSorter<String>()); } map.put("foo", new MarkerTypeTreeMap("foo")); map.put("bar", new MarkerTypeTreeMap("bar")); map.put("baz", new MarkerTypeTreeMap("baz")); map.put("bal", new MarkerTypeTreeMap("bal")); map.put("w00t", new MarkerTypeTreeMap("w00t")); return map; } public static TreeSet<MarkerTypeTreeSet> createTreeSet(boolean defaultComparator) { TreeSet<MarkerTypeTreeSet> set; if (defaultComparator) { set = new TreeSet<MarkerTypeTreeSet>(); } else { set = new TreeSet<MarkerTypeTreeSet>(new ReverseSorter<MarkerTypeTreeSet>()); } set.add(new MarkerTypeTreeSet("foo")); set.add(new MarkerTypeTreeSet("bar")); set.add(new MarkerTypeTreeSet("baz")); set.add(new MarkerTypeTreeSet("bal")); set.add(new MarkerTypeTreeSet("w00t")); return set; } public static Vector<MarkerTypeVector> createVector() { Vector<MarkerTypeVector> vector = new Vector<MarkerTypeVector>(); vector.add(new MarkerTypeVector("foo")); vector.add(new MarkerTypeVector("bar")); vector.add(new MarkerTypeVector("baz")); vector.add(new MarkerTypeVector("bal")); vector.add(new MarkerTypeVector("w00t")); return vector; } public static int[] createVeryLargeArray() { return new int[1 << 20]; } static SerializableDoublyLinkedNode createAcyclicGraph() { SerializableDoublyLinkedNode head = new SerializableDoublyLinkedNode(); head.setData("head"); SerializableDoublyLinkedNode leftChild = new SerializableDoublyLinkedNode(); leftChild.setData("lchild"); SerializableDoublyLinkedNode rightChild = new SerializableDoublyLinkedNode(); rightChild.setData("rchild"); head.setLeftChild(leftChild); head.setRightChild(rightChild); return head; } static SerializableDoublyLinkedNode createComplexCyclicGraph() { SerializableDoublyLinkedNode n1 = new SerializableDoublyLinkedNode(); n1.setData("n0"); SerializableDoublyLinkedNode n2 = new SerializableDoublyLinkedNode(); n2.setData("n1"); SerializableDoublyLinkedNode n3 = new SerializableDoublyLinkedNode(); n3.setData("n2"); SerializableDoublyLinkedNode n4 = new SerializableDoublyLinkedNode(); n4.setData("n3"); n1.setLeftChild(n4); n1.setRightChild(n2); n2.setLeftChild(n1); n2.setRightChild(n3); n3.setLeftChild(n2); n3.setRightChild(n4); n4.setLeftChild(n3); n4.setRightChild(n1); return n1; } static SerializableWithTwoArrays createDoublyReferencedArray() { SerializableWithTwoArrays o = new SerializableWithTwoArrays(); o.two = o.one = createStringArray(); return o; } static SerializableDoublyLinkedNode createTrivialCyclicGraph() { SerializableDoublyLinkedNode root = new SerializableDoublyLinkedNode(); root.setData("head"); root.setLeftChild(root); root.setRightChild(root); return root; } public static UmbrellaException createUmbrellaException() { Set<Throwable> causes = new HashSet<Throwable>(); UmbrellaException exception = new UmbrellaException(causes); SerializationException e1 = new SerializationException("Test Message 1", exception); SerializationException e2 = new SerializationException("Test Message 2", e1); causes.add(e1); causes.add(e2); return exception; } }