/* * 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.jdbi.v3.core.internal; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Implements Iterator methods for unidentified arrays and Iterable things that do not * have a more specific type than Object. Note that its elements will be returned as * Object, primitives included (will be autoboxed). */ public class IterableLike { /** * @return whether {@code ReflectionArrayIterator} can iterate over the given object */ public static boolean isIterable(Object maybeIterable) { return maybeIterable instanceof Iterator<?> || maybeIterable instanceof Iterable<?> || maybeIterable.getClass().isArray(); } /** * Given an iterable object (which may be a iterator, iterable, primitive * or reference array), return an iterator over its (possibly boxed) elements. * * @return an iterator of the given array's elements */ @SuppressWarnings("unchecked") public static Iterator<Object> of(Object iterable) { if (iterable == null) { throw new IllegalArgumentException("can't iterate null"); } if (iterable instanceof Iterator<?>) { return (Iterator<Object>) iterable; } else if (iterable instanceof Iterable<?>) { return ((Iterable<Object>) iterable).iterator(); } Class<? extends Object> klass = iterable.getClass(); if(!klass.isArray()) { throw new IllegalArgumentException(getTypeWarning(klass)); } if (klass.getComponentType().isPrimitive()) { return new PrimitiveArrayIterator(iterable); } return Arrays.asList((Object[])iterable).iterator(); } /** * Attempt to determine if a iterable-like is empty, preferably without iterating. * @param obj the iterable-like to check for emptiness * @return emptiness to fill your heart */ public static boolean isEmpty(final Object obj) { if (obj == null) { throw new IllegalArgumentException("cannot determine emptiness of null"); } if (obj instanceof Collection) { return ((Collection<?>) obj).isEmpty(); } if (obj instanceof Iterable) { return !((Iterable<?>) obj).iterator().hasNext(); } if (obj.getClass().isArray()) { return Array.getLength(obj) == 0; } throw new IllegalArgumentException(getTypeWarning(obj.getClass())); } /** * Collect an iterable-like into a newly allocated ArrayList. * @param iterable the iterable-like to collect * @return a new list with the elements */ public static List<Object> toList(Object iterable) { List<Object> result = new ArrayList<Object>(); of(iterable).forEachRemaining(result::add); return result; } private static String getTypeWarning(final Class<?> type) { return "argument must be one of the following: Iterable, or an array/varargs (primitive or complex type); was " + type.getName() + " instead"; } static class PrimitiveArrayIterator implements Iterator<Object> { private int index = 0; private final int size; private final Object arr; /** * @throws IllegalArgumentException if obj is not an array */ PrimitiveArrayIterator(final Object obj) { size = Array.getLength(obj); arr = obj; } @Override public boolean hasNext() { return index < size; } @Override public Object next() { if (hasNext()) { return Array.get(arr, index++); } else { throw new NoSuchElementException("only " + size + " elements available"); } } @Override public void remove() { throw new UnsupportedOperationException(); } } }