From 19269205e32c63bb4e931d144dcd3b1ba41cf3db Mon Sep 17 00:00:00 2001 From: Yu Kobayashi Date: Thu, 31 Jul 2014 07:00:21 +0900 Subject: [PATCH] GROOVY-6928: Support all the Java 6 classes at createSimilarCollection() and createSimilarMap() --- .../runtime/DefaultGroovyMethodsSupport.java | 115 +++++++++--- .../DefaultGroovyMethodsSupportTest.groovy | 170 ++++++++++++++++++ 2 files changed, 262 insertions(+), 23 deletions(-) create mode 100644 src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupportTest.groovy diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java index 437f5f5afa..dd18abb369 100644 --- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java +++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.lang.reflect.Array; import java.util.*; +import java.util.concurrent.*; import java.util.logging.Logger; /** @@ -154,7 +155,7 @@ protected static Collection createSimilarCollection(Collection orig, i return createSimilarList((List) orig, newCapacity); } if (orig instanceof Queue) { - return new LinkedList(); + return createSimilarQueue((Queue) orig); } return new ArrayList(newCapacity); } @@ -169,6 +170,9 @@ protected static List createSimilarList(List orig, int newCapacity) { if (orig instanceof Vector) return new Vector(); + if (orig instanceof CopyOnWriteArrayList) + return new CopyOnWriteArrayList(); + return new ArrayList(newCapacity); } @@ -181,23 +185,75 @@ protected static T[] createSimilarArray(T[] orig, int newCapacity) { @SuppressWarnings("unchecked") protected static Set createSimilarSet(Set orig) { if (orig instanceof SortedSet) { - return new TreeSet(((SortedSet)orig).comparator()); + Comparator comparator = ((SortedSet) orig).comparator(); + if (orig instanceof ConcurrentSkipListSet) { + return new ConcurrentSkipListSet(comparator); + } else { + return new TreeSet(comparator); + } + } else { + if (orig instanceof CopyOnWriteArraySet) { + return new CopyOnWriteArraySet(); + } else { + // Do not use HashSet + return new LinkedHashSet(); + } + } + } + + @SuppressWarnings("unchecked") + protected static Queue createSimilarQueue(Queue orig) { + if (orig instanceof ArrayBlockingQueue) { + ArrayBlockingQueue queue = (ArrayBlockingQueue) orig; + return new ArrayBlockingQueue(queue.size() + queue.remainingCapacity()); + } else if (orig instanceof ArrayDeque) { + return new ArrayDeque(); + } else if (orig instanceof ConcurrentLinkedQueue) { + return new ConcurrentLinkedQueue(); + } else if (orig instanceof DelayQueue) { + return new DelayQueue(); + } else if (orig instanceof LinkedBlockingDeque) { + return new LinkedBlockingDeque(); + } else if (orig instanceof LinkedBlockingQueue) { + return new LinkedBlockingQueue(); + } else if (orig instanceof PriorityBlockingQueue) { + return new PriorityBlockingQueue(); + } else if (orig instanceof PriorityQueue) { + return new PriorityQueue(11, ((PriorityQueue) orig).comparator()); + } else if (orig instanceof SynchronousQueue) { + return new SynchronousQueue(); + } else { + return new LinkedList(); } - return new LinkedHashSet(); } @SuppressWarnings("unchecked") protected static Map createSimilarMap(Map orig) { if (orig instanceof SortedMap) { - return new TreeMap(((SortedMap)orig).comparator()); - } - if (orig instanceof Properties) { - return (Map) new Properties(); - } - if (orig instanceof Hashtable) { - return new Hashtable(); + Comparator comparator = ((SortedMap) orig).comparator(); + if (orig instanceof ConcurrentSkipListMap) { + return new ConcurrentSkipListMap(comparator); + } else { + return new TreeMap(comparator); + } + } else { + if (orig instanceof ConcurrentHashMap) { + return new ConcurrentHashMap(); + } else if (orig instanceof Hashtable) { + if (orig instanceof Properties) { + return (Map) new Properties(); + } else { + return new Hashtable(); + } + } else if (orig instanceof IdentityHashMap) { + return new IdentityHashMap(); + } else if (orig instanceof WeakHashMap) { + return new WeakHashMap(); + } else { + // Do not use HashMap + return new LinkedHashMap(); + } } - return new LinkedHashMap(); } @SuppressWarnings("unchecked") @@ -206,19 +262,32 @@ protected static Map createSimilarMap(Map orig) { if (answer != null) return answer; // fall back to some defaults - if (orig instanceof TreeMap) - return new TreeMap(orig); - - if (orig instanceof Properties) { - Map map = (Map) new Properties(); - map.putAll(orig); - return map; + if (orig instanceof SortedMap) { + if (orig instanceof ConcurrentSkipListMap) { + return new ConcurrentSkipListMap(orig); + } else { + return new TreeMap(orig); + } + } else { + if (orig instanceof ConcurrentHashMap) { + return new ConcurrentHashMap(orig); + } else if (orig instanceof Hashtable) { + if (orig instanceof Properties) { + Map map = (Map) new Properties(); + map.putAll(orig); + return map; + } else { + return new Hashtable(orig); + } + } else if (orig instanceof IdentityHashMap) { + return new IdentityHashMap(orig); + } else if (orig instanceof WeakHashMap) { + return new WeakHashMap(orig); + } else { + // Do not use HashMap + return new LinkedHashMap(orig); + } } - - if (orig instanceof Hashtable) - return new Hashtable(orig); - - return new LinkedHashMap(orig); } /** diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupportTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupportTest.groovy new file mode 100644 index 0000000000..e38e7037cd --- /dev/null +++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupportTest.groovy @@ -0,0 +1,170 @@ +/* + * Copyright 2003-2014 the original author or authors. + * + * 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 org.codehaus.groovy.runtime + +import java.util.concurrent.* + +import static org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport.createSimilarCollection +import static org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport.createSimilarMap + +/** + * @author Yu Kobayashi + */ +class DefaultGroovyMethodsSupportTest extends GroovyTestCase { + void testCreateSimilarCollectionForSets() { + def comparator = [ + compare: { a, b -> b <=> a }, + equals : { a, b -> a == b }, + ] as Comparator + + Set set1 = new ConcurrentSkipListSet(comparator) + Set set2 = createSimilarCollection(set1) + set2 << 1 << 2 << 3 + assert set2 instanceof ConcurrentSkipListSet + assert 3 == set2.head() + assert 1 == set2.last() + + set1 = new TreeSet(comparator) + set2 = createSimilarCollection(set1) + set2 << 1 << 2 << 3 + assert set2 instanceof TreeSet + assert 3 == set2.head() + assert 1 == set2.last() + + set1 = new CopyOnWriteArraySet() + set2 = createSimilarCollection(set1) + set2 << 1 << 2 << 3 + assert set2 instanceof CopyOnWriteArraySet + assert 1 in set2 + assert 3 in set2 + + set1 = new LinkedHashSet() + set2 = createSimilarCollection(set1) + set2 << 1 << 2 << 3 + assert set2 instanceof LinkedHashSet + assert 1 == set2.head() + assert 3 == set2.last() + + set1 = new HashSet() + set2 = createSimilarCollection(set1) + set2 << 1 << 2 << 3 + assert set2 instanceof LinkedHashSet // Not HashSet + assert 1 == set2.head() + assert 3 == set2.last() + } + + void testCreateSimilarCollectionForLists() { + [ + CopyOnWriteArrayList.class, + LinkedList.class, + Stack.class, + Vector.class, + ArrayList.class, + ].each { testCase -> + List list = createSimilarCollection(testCase.newInstance() as Collection) + list << 1 << 2 << 3 + assert testCase.is(list.getClass()) + assert 1 == list.head() + assert 3 == list.last() + } + } + + void testCreateSimilarCollectionForQueues() { + [ + LinkedBlockingDeque.class, + LinkedList.class, + ArrayDeque.class, + ArrayBlockingQueue.class, + ConcurrentLinkedQueue.class, + DelayQueue.class, + LinkedBlockingQueue.class, + PriorityBlockingQueue.class, + PriorityQueue.class, + SynchronousQueue.class, + ].each { testCase -> + Queue queue + if (testCase == ArrayBlockingQueue.class) { + queue = createSimilarCollection(new ArrayBlockingQueue(11)) + } else if (testCase == PriorityQueue.class) { + def comparator = [ + compare: { a, b -> b <=> a }, + equals : { a, b -> a == b }, + ] as Comparator + queue = createSimilarCollection(new PriorityQueue(13, comparator)) + assert comparator == ((PriorityQueue) queue).comparator() + } else { + queue = createSimilarCollection(testCase.newInstance() as Collection) + } + + assert testCase == queue.getClass() + + if (queue instanceof PriorityQueue) { + queue << 1 << 2 << 3 + assert 3 == queue.head() + } else if (queue instanceof DelayQueue) { + [1, 2, 3].each { int i -> + queue << ([ + getDelay : { TimeUnit unit -> i as long }, + compareTo: { Delayed o -> i <=> o.getDelay(null) }, + ] as Delayed) + } + assert 1 == (queue.head() as Delayed).getDelay(null) + assert 3 == (queue.last() as Delayed).getDelay(null) + } else if (queue instanceof SynchronousQueue) { + // Do not do a add test + } else { + queue << 1 << 2 << 3 + assert 1 == queue.head() + assert 3 == queue.last() + } + } + } + + void testCreateSimilarMap() { + def comparator = [ + compare: { a, b -> b <=> a }, + equals : { a, b -> a == b }, + ] as Comparator + [ + [ConcurrentSkipListMap.class, new ConcurrentSkipListMap(comparator)], + [TreeMap.class, new TreeMap(comparator)], + ].each { testCase -> + Map map = createSimilarMap(testCase[1] as Map) + map[1] = 2 + map[3] = 4 + assert testCase[0] == map.getClass() + assert comparator == ((SortedMap) map).comparator() + assert 2 == map[1] + } + + [ + ConcurrentHashMap.class, + Properties.class, + Hashtable.class, + IdentityHashMap.class, + WeakHashMap.class, + LinkedHashMap.class, + HashMap.class, + ].each { testCase -> + Map map = createSimilarMap(testCase.newInstance()) + map[1] = 2 + map[3] = 4 + assert testCase == map.getClass() || (HashMap.class == testCase && LinkedHashMap.class == map.getClass()) + assert 2 == map[1] + } + } +}