blob: a36bfb6d86e613b6e897ea73505684ac3b59f229 [file] [log] [blame]
// ***************************************************************************************************************************
// * 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.juneau.internal;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.ThrowableUtils.*;
import java.lang.reflect.*;
import java.util.*;
/**
* Quick and dirty utilities for working with arrays.
*/
public final class ArrayUtils {
/**
* Appends one or more elements to an array.
*
* @param <T> The element type.
* @param array The array to append to.
* @param newElements The new elements to append to the array.
* @return A new array with the specified elements appended.
*/
@SuppressWarnings("unchecked")
public static <T> T[] append(T[] array, T...newElements) {
if (array == null)
return newElements;
if (newElements.length == 0)
return array;
T[] a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.length);
for (int i = 0; i < array.length; i++)
a[i] = array[i];
for (int i = 0; i < newElements.length; i++)
a[i+array.length] = newElements[i];
return a;
}
/**
* Appends one or more elements to an array.
*
* @param <T> The element type.
* @param array The array to append to.
* @param newElements The new elements to append to the array.
* @return A new array with the specified elements appended.
*/
@SuppressWarnings("unchecked")
public static <T> T[] append(T[] array, Collection<T> newElements) {
assertFieldNotNull(array, "array");
if (newElements.size() == 0)
return array;
T[] a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.size());
for (int i = 0; i < array.length; i++)
a[i] = array[i];
int l = array.length;
for (T t : newElements)
a[l++] = t;
return a;
}
/**
* Combine an arbitrary number of arrays into a single array.
*
* @param arrays Collection of arrays to combine.
* @return A new combined array, or <jk>null</jk> if all arrays are <jk>null</jk>.
*/
@SuppressWarnings("unchecked")
public static <T> T[] combine(T[]...arrays) {
assertFieldNotNull(arrays, "arrays");
int l = 0;
T[] a1 = null;
for (T[] a : arrays) {
if (a1 == null && a != null)
a1 = a;
l += (a == null ? 0 : a.length);
}
if (a1 == null)
return null;
T[] a = (T[])Array.newInstance(a1.getClass().getComponentType(), l);
int i = 0;
for (T[] aa : arrays)
if (aa != null)
for (T t : aa)
a[i++] = t;
return a;
}
/**
* Creates a new array with reversed entries.
*
* @param <T> The class type of the array.
* @param array The array to reverse.
* @return A new array with reversed entries, or <jk>null</jk> if the array was <jk>null</jk>.
*/
@SuppressWarnings("unchecked")
public static <T> T[] reverse(T[] array) {
if (array == null)
return null;
Class<T> c = (Class<T>)array.getClass().getComponentType();
T[] a2 = (T[])Array.newInstance(c, array.length);
for (int i = 0; i < array.length; i++)
a2[a2.length-i-1] = array[i];
return a2;
}
/**
* Sorts the elements in an array without creating a new array.
*
* @param array The array to sort.
* @return The same array.
*/
public static <T> T[] reverseInline(T[] array) {
if (array == null)
return null;
T t;
for (int i = 0, j = array.length-1; i < j; i++, j--) {
t = array[i];
array[i] = array[j];
array[j] = t;
}
return array;
}
/**
* Converts the specified array to a <c>Set</c>.
*
* <p>
* The order of the entries in the set are the same as the array.
*
* @param <T> The entry type of the array.
* @param array The array being wrapped in a <c>Set</c> interface.
* @return The new set.
*/
public static <T> Set<T> asSet(final T[] array) {
assertFieldNotNull(array, "array");
return new AbstractSet<T>() {
@Override /* Set */
public Iterator<T> iterator() {
return new Iterator<T>() {
int i = 0;
@Override /* Iterator */
public boolean hasNext() {
return i < array.length;
}
@Override /* Iterator */
public T next() {
if (i >= array.length)
throw new NoSuchElementException();
T t = array[i];
i++;
return t;
}
@Override /* Iterator */
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override /* Set */
public int size() {
return array.length;
}
};
}
/**
* Returns an iterator against an array.
*
* <p>
* This works with any array type (e.g. <c>String[]</c>, <c>Object[]</c>,
* <code><jk>int</jk>[]</code>, etc...).
*
* @param array The array to create an iterator over.
* @return An iterator over the specified array.
*/
public static Iterator<Object> iterator(final Object array) {
return new Iterator<Object>() {
int i = 0;
int length = array == null ? 0 : Array.getLength(array);
@Override /* Iterator */
public boolean hasNext() {
return i < length;
}
@Override /* Iterator */
public Object next() {
if (i >= length)
throw new NoSuchElementException();
return Array.get(array, i++);
}
@Override /* Iterator */
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Converts the specified collection to an array.
*
* <p>
* Works on both object and primitive arrays.
*
* @param c The collection to convert to an array.
* @param componentType The component type of the collection.
* @return A new array.
*/
public static <T> Object toArray(Collection<?> c, Class<T> componentType) {
Object a = Array.newInstance(componentType, c.size());
Iterator<?> it = c.iterator();
int i = 0;
while (it.hasNext())
Array.set(a, i++, it.next());
return a;
}
/**
* Returns <jk>true</jk> if the specified object is an array.
*
* @param array The array to test.
* @return <jk>true</jk> if the specified object is an array.
*/
public static boolean isArray(Object array) {
return array != null && array.getClass().isArray();
}
/**
* Converts the specified array to an <c>ArrayList</c>
*
* @param array The array to convert.
* @param componentType
* The type of objects in the array.
* It must match the actual component type in the array.
* @return A new {@link ArrayList}
*/
@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object array, Class<T> componentType) {
List<T> l = new ArrayList<>(Array.getLength(array));
for (int i = 0; i < Array.getLength(array); i++)
l.add((T)Array.get(array, i));
return l;
}
/**
* Shortcut for calling <c>myList.toArray(new T[myList.size()]);</c>
*
* @param c The collection being converted to an array.
* @param componentType The component type of the array.
* @return The collection converted to an array.
*/
@SuppressWarnings("unchecked")
public static <T> T[] toObjectArray(Collection<?> c, Class<T> componentType) {
Object a = Array.newInstance(componentType, c.size());
Iterator<?> it = c.iterator();
int i = 0;
while (it.hasNext())
Array.set(a, i++, it.next());
return (T[])a;
}
/**
* Copies the specified array into the specified list.
*
* <p>
* Works on both object and primitive arrays.
*
* @param array The array to copy into a list.
* @param list The list to copy the values into.
* @return The same list passed in.
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static List copyToList(Object array, List list) {
if (array != null) {
int length = Array.getLength(array);
for (int i = 0; i < length; i++)
list.add(Array.get(array, i));
}
return list;
}
/**
* Returns <jk>true</jk> if the specified array contains the specified element using the {@link Object#equals(Object)}
* method.
*
* @param element The element to check for.
* @param array The array to check.
* @return
* <jk>true</jk> if the specified array contains the specified element,
* <jk>false</jk> if the array or element is <jk>null</jk>.
*/
public static <T> boolean contains(T element, T[] array) {
return indexOf(element, array) != -1;
}
/**
* Returns <jk>true</jk> if the specified array contains the specified integer
*
* @param element The element to check for.
* @param array The array to check.
* @return
* <jk>true</jk> if the specified array contains the specified element,
* <jk>false</jk> if the array or element is <jk>null</jk>.
*/
public static boolean contains(int element, int[] array) {
if (array != null)
for (int i : array)
if (element == i)
return true;
return false;
}
/**
* Returns the index position of the element in the specified array using the {@link Object#equals(Object)} method.
*
* @param element The element to check for.
* @param array The array to check.
* @return
* The index position of the element in the specified array, or <c>-1</c> if the array doesn't contain the
* element, or the array or element is <jk>null</jk>.
*/
public static <T> int indexOf(T element, T[] array) {
if (element == null)
return -1;
if (array == null)
return -1;
for (int i = 0; i < array.length; i++)
if (element.equals(array[i]))
return i;
return -1;
}
/**
* Returns <jk>true</jk> if the specified array contains the specified element using the {@link String#equals(Object)}
* method.
*
* @param element The element to check for.
* @param array The array to check.
* @return
* <jk>true</jk> if the specified array contains the specified element,
* <jk>false</jk> if the array or element is <jk>null</jk>.
*/
public static boolean contains(String element, String[] array) {
return indexOf(element, array) != -1;
}
/**
* Returns the index position of the element in the specified array using the {@link String#equals(Object)} method.
*
* @param element The element to check for.
* @param array The array to check.
* @return
* The index position of the element in the specified array, or
* <c>-1</c> if the array doesn't contain the element, or the array or element is <jk>null</jk>.
*/
public static int indexOf(String element, String[] array) {
if (element == null)
return -1;
if (array == null)
return -1;
for (int i = 0; i < array.length; i++)
if (element.equals(array[i]))
return i;
return -1;
}
/**
* Converts a primitive wrapper array (e.g. <c>Integer[]</c>) to a primitive array (e.g. <code><jk>int</jk>[]</code>).
*
* @param o The array to convert. Must be a primitive wrapper array.
* @return A new array.
* @throws IllegalArgumentException If object is not a wrapper object array.
*/
public static Object toPrimitiveArray(Object o) {
Class<?> c = o.getClass();
if (! c.isArray())
throw new IllegalArgumentException("Cannot pass non-array objects to toPrimitiveArray()");
int l = Array.getLength(o);
Class<?> tc = getClassInfo(c.getComponentType()).getPrimitiveForWrapper();
if (tc == null)
throw new IllegalArgumentException("Array type is not a primitive wrapper array.");
Object a = Array.newInstance(tc, l);
for (int i = 0; i < l; i++)
Array.set(a, i, Array.get(o, i));
return a;
}
/**
* Converts an Iterable to a list.
*
* @param i The iterable to convert.
* @return A new list of objects copied from the iterable.
*/
public static List<?> toList(Iterable<?> i) {
List<Object> l = new ArrayList<>();
Iterator<?> i2 = i.iterator();
while (i2.hasNext())
l.add(i2.next());
return l;
}
/**
* Returns the first object in the specified collection or array.
*
* @param val The collection or array object.
* @return
* The first object, or <jk>null</jk> if the collection or array is empty or <jk>null</jk> or the value
* isn't a collection or array.
*/
public static Object getFirst(Object val) {
if (val != null) {
if (val instanceof Collection) {
Collection<?> c = (Collection<?>)val;
if (c.isEmpty())
return null;
return c.iterator().next();
}
if (val.getClass().isArray())
return Array.getLength(val) == 0 ? null : Array.get(val, 0);
}
return null;
}
/**
* Converts the specified collection to an array of strings.
*
* <p>
* Entries are converted to strings using {@link #toString()}.
* <jk>null</jk> values remain <jk>null</jk>.
*
* @param c The collection to convert.
* @return The collection as a string array.
*/
public static String[] toStringArray(Collection<?> c) {
String[] r = new String[c.size()];
int i = 0;
for (Object o : c)
r[i++] = stringify(o);
return r;
}
/**
* Returns <jk>true</jk> if the following sorted arrays are equals.
*
* @param a1 Array #1.
* @param a2 Array #2.
* @return <jk>true</jk> if the following sorted arrays are equals.
*/
public static boolean equals(String[] a1, String[] a2) {
if (a1.length != a2.length)
return false;
for (int i = 0; i < a1.length; i++)
if (! StringUtils.isEquals(a1[i], a2[i]))
return false;
return true;
}
/**
* Converts a collection to an array containing the elements in reversed order.
*
* @param c The component type of the array.
* @param l
* The collection to convert.
* <br>The collection is not modified.
* @return
* A new array, or <jk>null</jk> if the collection was <jk>null</jk>.
*/
@SuppressWarnings("unchecked")
public static <T> T[] toReverseArray(Class<T> c, Collection<T> l) {
if (l == null)
return null;
Object a = Array.newInstance(c, l.size());
Iterator<T> i = l.iterator();
int j = l.size();
while (i.hasNext())
Array.set(a, --j, i.next());
return (T[])a;
}
/**
* Removes the specified element from the specified array.
*
* @param element The element to remove from the array.
* @param array The array to remove the element from.
* @return A new array with the element removed, or the original array if the array did not contain the element.
*/
public static Object[] remove(Object element, Object[] array) {
if (! contains(element, array))
return array;
List<Object> l = new ArrayList<>(array.length);
for (Object o2 : array) {
if (! element.equals(o2))
l.add(o2);
}
return l.toArray(new Object[l.size()]);
}
}