Author: rwhitcomb Date: Mon Aug 12 22:09:58 2019 New Revision: 1864990 URL: http://svn.apache.org/viewvc?rev=1864990&view=rev Log: PIVOT-1045: Start refactoring the read-only collections to use a common base class: * Implement ReadOnlySequence which just throws the exception for the applicable methods. * Redo ArrayAdapter, EnumList, ImmutableList, and NumericSpinnerData as the first fruits. * Misc. changes to ArrayList to spiff it up, including removing the now redundant "addAll" method, adding a constructor with capacity and comparator and redoing binarySearch to use the default comparator from Arrays.binarySearch. Add a test of that to ArrayListTest. * Correct some small style errors as well (mostly Javadoc and final parameters).
Added: pivot/trunk/core/src/org/apache/pivot/collections/ReadOnlySequence.java Modified: pivot/trunk/core/src/org/apache/pivot/collections/ArrayAdapter.java pivot/trunk/core/src/org/apache/pivot/collections/ArrayList.java pivot/trunk/core/src/org/apache/pivot/collections/EnumList.java pivot/trunk/core/src/org/apache/pivot/collections/immutable/ImmutableList.java pivot/trunk/core/test/org/apache/pivot/collections/test/ArrayListTest.java pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java Modified: pivot/trunk/core/src/org/apache/pivot/collections/ArrayAdapter.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/collections/ArrayAdapter.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/collections/ArrayAdapter.java (original) +++ pivot/trunk/core/src/org/apache/pivot/collections/ArrayAdapter.java Mon Aug 12 22:09:58 2019 @@ -18,63 +18,35 @@ package org.apache.pivot.collections; import java.io.Serializable; -import org.apache.pivot.annotations.UnsupportedOperation; import org.apache.pivot.util.Utils; /** * A read-only implementation of the {@link Sequence} interface that wraps an array. + * <p> Used to interface between a Java array and a Pivot control that expects a + * {@link Sequence} of objects (such as a {@code TablePane}, {@code Menu}, {@code ListView} + * or similar). + * + * @param <T> The underlying type of the array objects. */ -public class ArrayAdapter<T> implements Sequence<T>, Serializable { +public class ArrayAdapter<T> extends ReadOnlySequence<T> implements Serializable { private static final long serialVersionUID = 1143706808122308239L; - private static final String ERROR_MSG = "An Array Adapter is immutable."; - private T[] array; @SuppressWarnings({ "unchecked" }) - public ArrayAdapter(T... array) { + public ArrayAdapter(final T... array) { Utils.checkNull(array, "array"); this.array = array; } @Override - @UnsupportedOperation - public int add(T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public void insert(T item, int index) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public T update(int index, T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public int remove(T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public Sequence<T> remove(int index, int count) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - public T get(int index) { + public T get(final int index) { return array[index]; } @Override - public int indexOf(T item) { + public int indexOf(final T item) { for (int index = 0; index < array.length; index++) { if ((item == null && array[index] == null) || item.equals(array[index])) { return index; Modified: pivot/trunk/core/src/org/apache/pivot/collections/ArrayList.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/collections/ArrayList.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/collections/ArrayList.java (original) +++ pivot/trunk/core/src/org/apache/pivot/collections/ArrayList.java Mon Aug 12 22:09:58 2019 @@ -154,7 +154,7 @@ public class ArrayList<T> implements Lis } /** - * Construct a new ArrayList sorted by the given comparator, with the + * Construct a new ArrayList to be sorted by the given comparator, with the * default capacity. * * @param comparator A comparator to sort the entries in the list. @@ -177,6 +177,18 @@ public class ArrayList<T> implements Lis } /** + * Construct a new ArrayList to be sorted by the given comparator, + * with the given capacity. + * + * @param capacity The initial capacity for this list. + * @param comparator The comparator to use when sorting the list. + */ + public ArrayList(final int capacity, final Comparator<T> comparator) { + this(capacity); + this.comparator = comparator; + } + + /** * Construct a new ArrayList with the given list of items. * * @param items The initial list of values for the list. @@ -465,17 +477,6 @@ public class ArrayList<T> implements Lis } /** - * Add all the elements of the given collection to this list. - * - * @param collection The collection whose elements should be added. - */ - public void addAll(final Collection<T> collection) { - for (T item : collection) { - add(item); - } - } - - /** * Trim the internal storage for this list to exactly fit the current * number of items in it. */ @@ -676,16 +677,18 @@ public class ArrayList<T> implements Lis * @param <T> Type of the list elements. * @param arrayList The list to search. * @param item The item to search for in the list. - * @param comparator Comparator to use for testing. + * @param comparator Comparator to use for testing; if {@code null} then the "natural" ordering of the objects + * is used (see the caveats of {@link Arrays#binarySearch(Object[], Object)}). * @return The index of the item in the list if found, or -1 if the item cannot be found in the list. */ @SuppressWarnings("unchecked") public static <T> int binarySearch(final ArrayList<T> arrayList, final T item, final Comparator<T> comparator) { Utils.checkNull(arrayList, "arrayList"); - Utils.checkNull(comparator, "comparator"); Utils.checkNull(item, "item"); - int index = Arrays.binarySearch((T[]) arrayList.items, 0, arrayList.length, item, comparator); + int index = (comparator == null) + ? Arrays.binarySearch((T[]) arrayList.items, 0, arrayList.length, item) + : Arrays.binarySearch((T[]) arrayList.items, 0, arrayList.length, item, comparator); return index; } @@ -699,7 +702,7 @@ public class ArrayList<T> implements Lis * @return The index of the item in the list if found, or -1 if the item is not found. */ public static <T extends Comparable<? super T>> int binarySearch(final ArrayList<T> arrayList, final T item) { - return binarySearch(arrayList, item, (o1, o2) -> o1.compareTo(o2)); + return binarySearch(arrayList, item, null); } } Modified: pivot/trunk/core/src/org/apache/pivot/collections/EnumList.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/collections/EnumList.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/collections/EnumList.java (original) +++ pivot/trunk/core/src/org/apache/pivot/collections/EnumList.java Mon Aug 12 22:09:58 2019 @@ -35,12 +35,12 @@ import org.apache.pivot.util.Utils; * (for instance). A useful way to do this is to override the {@code "toString()"} method of * the enum to provide a human-readable version of the enum constant value, which will then * appear in the UI. + * + * @param <E> The underlying enum type that backs this list. */ -public class EnumList<E extends Enum<E>> implements List<E>, Serializable { +public class EnumList<E extends Enum<E>> extends ReadOnlySequence<E> implements List<E>, Serializable { private static final long serialVersionUID = 5104856822133576300L; - private static final String ERROR_MSG = "An Enum List cannot be modified."; - private class ItemIterator implements Iterator<E> { private int i = 0; @@ -61,7 +61,7 @@ public class EnumList<E extends Enum<E>> @Override @UnsupportedOperation public void remove() { - throw new UnsupportedOperationException(ERROR_MSG); + throw new UnsupportedOperationException(unsupportedOperationMsg); } } @@ -75,7 +75,7 @@ public class EnumList<E extends Enum<E>> * * @param enumClass The enum class whose constant values are used to fully populate the list. */ - public EnumList(Class<E> enumClass) { + public EnumList(final Class<E> enumClass) { this.enumClass = enumClass; items = enumClass.getEnumConstants(); } @@ -86,47 +86,17 @@ public class EnumList<E extends Enum<E>> @Override @UnsupportedOperation - public int add(E item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public void insert(E item, int index) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public E update(int index, E item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public int remove(E item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public Sequence<E> remove(int index, int count) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation public void clear() { - throw new UnsupportedOperationException(ERROR_MSG); + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override - public E get(int index) { + public E get(final int index) { return items[index]; } @Override - public int indexOf(E item) { + public int indexOf(final E item) { Utils.checkNull(item, "item"); return item.ordinal(); @@ -146,15 +116,25 @@ public class EnumList<E extends Enum<E>> return Arrays.copyOf(items, items.length); } + /** + * Always returns {@code null} because there can never be a {@link Comparator} + * set to change from the "natural" ordering of the {@code Enum}. + * @return {@code null} always. + */ @Override public Comparator<E> getComparator() { return null; } + /** + * Unsupported because the list is always ordered in the "natural" order of the + * backing {@code Enum}. + * @throws UnsupportedOperationException always. + */ @Override @UnsupportedOperation - public void setComparator(Comparator<E> comparator) { - throw new UnsupportedOperationException(ERROR_MSG); + public void setComparator(final Comparator<E> comparator) { + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override @@ -189,7 +169,7 @@ public class EnumList<E extends Enum<E>> @Override @SuppressWarnings("unchecked") - public boolean equals(Object o) { + public boolean equals(final Object o) { return (o instanceof EnumList<?> && ((EnumList<E>) o).enumClass == enumClass); } Added: pivot/trunk/core/src/org/apache/pivot/collections/ReadOnlySequence.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/collections/ReadOnlySequence.java?rev=1864990&view=auto ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/collections/ReadOnlySequence.java (added) +++ pivot/trunk/core/src/org/apache/pivot/collections/ReadOnlySequence.java Mon Aug 12 22:09:58 2019 @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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.apache.pivot.collections; + +import java.io.Serializable; + +import org.apache.pivot.annotations.UnsupportedOperation; + +/** + * A read-only implementation of the {@link Sequence} interface that can be used + * to easily implement other read-only sequences, lists, adapters, etc. + * <p> "Read-only" because all operations (such as {@link #add}, {@link #insert}, + * and etc. will throw {@link UnsupportedOperationException} and are marked with + * {@link UnsupportedOperation} annotation. + * + * @param <T> The base type of objects in this sequence. + */ +public abstract class ReadOnlySequence<T> implements Sequence<T>, Serializable { + private static final long serialVersionUID = -2547032333033014540L; + + /** The message passed to the {@link UnsupportedOperationException} to say this + * sequence is read-only and cannot be modified. + */ + protected final String unsupportedOperationMsg = + "A(n) " + this.getClass().getSimpleName() + " is read-only (immutable)."; + + /** + * Adding an item to a read-only sequence is unsupported. + * @throws UnsupportedOperationException always + */ + @Override + @UnsupportedOperation + public final int add(final T item) { + throw new UnsupportedOperationException(unsupportedOperationMsg); + } + + /** + * Inserting an item into a read-only sequence is unsupported. + * @throws UnsupportedOperationException always + */ + @Override + @UnsupportedOperation + public final void insert(final T item, final int index) { + throw new UnsupportedOperationException(unsupportedOperationMsg); + } + + /** + * Updating an item in a read-only sequence is unsupported. + * @throws UnsupportedOperationException always + */ + @Override + @UnsupportedOperation + public final T update(final int index, final T item) { + throw new UnsupportedOperationException(unsupportedOperationMsg); + } + + /** + * Removing an item from a read-only sequence is unsupported. + * @throws UnsupportedOperationException always + */ + @Override + @UnsupportedOperation + public final int remove(final T item) { + throw new UnsupportedOperationException(unsupportedOperationMsg); + } + + /** + * Removing an item from a read-only sequence is unsupported. + * @throws UnsupportedOperationException always + */ + @Override + @UnsupportedOperation + public final Sequence<T> remove(final int index, final int count) { + throw new UnsupportedOperationException(unsupportedOperationMsg); + } + +} Modified: pivot/trunk/core/src/org/apache/pivot/collections/immutable/ImmutableList.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/collections/immutable/ImmutableList.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/collections/immutable/ImmutableList.java (original) +++ pivot/trunk/core/src/org/apache/pivot/collections/immutable/ImmutableList.java Mon Aug 12 22:09:58 2019 @@ -22,7 +22,7 @@ import java.util.Iterator; import org.apache.pivot.annotations.UnsupportedOperation; import org.apache.pivot.collections.List; import org.apache.pivot.collections.ListListener; -import org.apache.pivot.collections.Sequence; +import org.apache.pivot.collections.ReadOnlySequence; import org.apache.pivot.util.ImmutableIterator; import org.apache.pivot.util.ListenerList; import org.apache.pivot.util.Utils; @@ -31,12 +31,12 @@ import org.apache.pivot.util.Utils; * Unmodifiable implementation of the {@link List} interface. * @param <T> Type of elements in this list. */ -public final class ImmutableList<T> implements List<T> { - private List<T> list = null; +public final class ImmutableList<T> extends ReadOnlySequence<T> implements List<T> { + private static final long serialVersionUID = 3506674138756807777L; - private ListListenerList<T> listListeners = new ListListenerList<>(); + private List<T> list = null; - private static final String ERROR_MSG = "An Immutable List cannot be modified."; + private transient ListListenerList<T> listListeners = new ListListenerList<>(); public ImmutableList(final List<T> list) { Utils.checkNull(list, "list"); @@ -46,38 +46,8 @@ public final class ImmutableList<T> impl @Override @UnsupportedOperation - public int add(final T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public void insert(final T item, final int index) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public T update(final int index, final T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public int remove(final T item) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation - public Sequence<T> remove(final int index, final int count) { - throw new UnsupportedOperationException(ERROR_MSG); - } - - @Override - @UnsupportedOperation public void clear() { - throw new UnsupportedOperationException(ERROR_MSG); + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override @@ -108,7 +78,7 @@ public final class ImmutableList<T> impl @Override @UnsupportedOperation public void setComparator(final Comparator<T> comparator) { - throw new UnsupportedOperationException(ERROR_MSG); + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override Modified: pivot/trunk/core/test/org/apache/pivot/collections/test/ArrayListTest.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/collections/test/ArrayListTest.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/core/test/org/apache/pivot/collections/test/ArrayListTest.java (original) +++ pivot/trunk/core/test/org/apache/pivot/collections/test/ArrayListTest.java Mon Aug 12 22:09:58 2019 @@ -102,6 +102,9 @@ public class ArrayListTest { iterator.toStart(); assertEquals(iterator.next(), "M"); + + ArrayList.sort(list); + assertEquals(ArrayList.binarySearch(list, "N"), 4); } @Test Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java?rev=1864990&r1=1864989&r2=1864990&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java Mon Aug 12 22:09:58 2019 @@ -24,7 +24,7 @@ import java.util.NoSuchElementException; import org.apache.pivot.annotations.UnsupportedOperation; import org.apache.pivot.collections.List; import org.apache.pivot.collections.ListListener; -import org.apache.pivot.collections.Sequence; +import org.apache.pivot.collections.ReadOnlySequence; import org.apache.pivot.util.ListenerList; /** @@ -34,7 +34,7 @@ import org.apache.pivot.util.ListenerLis * <i>fail-fast</i>: if the bounds of the enclosing spinner data change during * iteration, a <tt>ConcurrentModificationException</tt> will be thrown. */ -public class NumericSpinnerData implements List<Integer> { +public class NumericSpinnerData extends ReadOnlySequence<Integer> implements List<Integer> { private class DataIterator implements Iterator<Integer> { // Parity members to support ConcurrentModificationException check @@ -72,11 +72,13 @@ public class NumericSpinnerData implemen } } + private static final long serialVersionUID = 6703972744166403263L; + private int lowerBound; private int upperBound; private int increment; - private ListListenerList<Integer> listListeners = new ListListenerList<>(); + private transient ListListenerList<Integer> listListeners = new ListListenerList<>(); /** * Creates a new <tt>NumericSpinnerData</tt> instance bounded from @@ -94,7 +96,7 @@ public class NumericSpinnerData implemen * @param lowerBound The lower bound for the data. * @param upperBound The upper bound for the data. */ - public NumericSpinnerData(int lowerBound, int upperBound) { + public NumericSpinnerData(final int lowerBound, final int upperBound) { this(lowerBound, upperBound, 1); } @@ -106,7 +108,7 @@ public class NumericSpinnerData implemen * @param upperBound The upper bound for the data. * @param increment The increment between values. */ - public NumericSpinnerData(int lowerBound, int upperBound, int increment) { + public NumericSpinnerData(final int lowerBound, final int upperBound, final int increment) { if (lowerBound >= upperBound) { throw new IllegalArgumentException("Lower bound must be less than upper bound."); } @@ -126,7 +128,7 @@ public class NumericSpinnerData implemen return lowerBound; } - public void setLowerBound(int lowerBound) { + public void setLowerBound(final int lowerBound) { this.lowerBound = lowerBound; } @@ -134,7 +136,7 @@ public class NumericSpinnerData implemen return upperBound; } - public void setUpperBound(int upperBound) { + public void setUpperBound(final int upperBound) { this.upperBound = upperBound; } @@ -142,62 +144,12 @@ public class NumericSpinnerData implemen return increment; } - public void setIncrement(int increment) { + public void setIncrement(final int increment) { this.increment = increment; } - /** - * Not supported in this class. - * @throws UnsupportedOperationException always. - */ - @UnsupportedOperation - @Override - public int add(Integer item) { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this class. - * @throws UnsupportedOperationException always. - */ - @UnsupportedOperation - @Override - public void insert(Integer item, int index) { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this class. - * @throws UnsupportedOperationException always. - */ - @UnsupportedOperation - @Override - public Integer update(int index, Integer item) { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this class. - * @throws UnsupportedOperationException always. - */ - @UnsupportedOperation - @Override - public int remove(Integer item) { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this class. - * @throws UnsupportedOperationException always. - */ - @UnsupportedOperation - @Override - public Sequence<Integer> remove(int index, int count) { - throw new UnsupportedOperationException(); - } - @Override - public Integer get(int index) { + public Integer get(final int index) { if (index < 0 || index >= getLength()) { throw new IndexOutOfBoundsException("Invalid index: " + index); } @@ -206,7 +158,7 @@ public class NumericSpinnerData implemen } @Override - public int indexOf(Integer item) { + public int indexOf(final Integer item) { int index = -1; if (item >= lowerBound && item <= upperBound) { @@ -228,7 +180,7 @@ public class NumericSpinnerData implemen @UnsupportedOperation @Override public void clear() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override @@ -256,8 +208,8 @@ public class NumericSpinnerData implemen */ @UnsupportedOperation @Override - public void setComparator(Comparator<Integer> comparator) { - throw new UnsupportedOperationException(); + public void setComparator(final Comparator<Integer> comparator) { + throw new UnsupportedOperationException(unsupportedOperationMsg); } @Override