/*
 * 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.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.jdbi.v3.core.generic.GenericTypes;

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).
/** * 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 { private IterableLike() { throw new UtilityClassException(); }
Params:
  • maybeIterable – the object that might be iterable
Returns:whether IterableLike can iterate over the given object
/** * @param maybeIterable the object that might be iterable * @return whether {@code IterableLike} 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.
Params:
  • iterable – the iterable-like
Returns:an iterator of the given array's elements
/** * Given an iterable object (which may be a iterator, iterable, primitive * or reference array), return an iterator over its (possibly boxed) elements. * * @param iterable the iterable-like * @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<?> 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(); }
Given an iterable-like object, try to determine its static (i.e, without looking at contents) element type.
/** Given an iterable-like object, try to determine its static (i.e, without looking at contents) element type. */
public static Optional<Type> elementTypeOf(Object iterable) { return elementTypeOf(iterable.getClass()); }
Given an iterable-like type, try to determine its static (i.e, without looking at contents) element type.
/** Given an iterable-like type, try to determine its static (i.e, without looking at contents) element type. */
public static Optional<Type> elementTypeOf(Type type) { final Class<?> rawClass = GenericTypes.getErasedType(type); if (rawClass.isArray()) { return Optional.of(rawClass.getComponentType()); } else if (Iterable.class.isAssignableFrom(rawClass)) { return GenericTypes.findGenericParameter(type, Iterable.class); } else if (Iterator.class.isAssignableFrom(rawClass)) { return GenericTypes.findGenericParameter(type, Iterator.class); } else { // not an iterable-like return Optional.empty(); } }
Given an iterable object (which may be a iterator, iterable, primitive or reference array), return a Stream over its (possibly boxed) elements.
Returns:a stream of the given array's elements
/** * Given an iterable object (which may be a iterator, iterable, primitive * or reference array), return a {@link Stream} over its (possibly boxed) elements. * * @return a stream of the given array's elements */
public static Stream<Object> stream(Object iterable) { return StreamSupport.stream(Spliterators.spliteratorUnknownSize(of(iterable), Spliterator.ORDERED), false); }
Given an iterable object (which may be a iterator, iterable, primitive or reference array), return an iterable over its (possibly boxed) elements.
Params:
  • iterable – the iterable-like to create a real Iterable for
Returns:the created Iterable
/** * Given an iterable object (which may be a iterator, iterable, primitive * or reference array), return an iterable over its (possibly boxed) elements. * @param iterable the iterable-like to create a real Iterable for * @return the created Iterable */
public static Iterable<Object> iterable(Object iterable) { return () -> of(iterable); }
Attempt to determine if a iterable-like is empty, preferably without iterating.
Params:
  • obj – the iterable-like to check for emptiness
Returns:emptiness to fill your heart
/** * 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.
Params:
  • iterable – the iterable-like to collect
Returns:a new list with the elements
/** * 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
/** * @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(); } } }