/*
 * 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.generic;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import java.util.Optional;

import io.leangen.geantyref.GenericTypeReflector;
import io.leangen.geantyref.TypeFactory;
import org.jdbi.v3.core.internal.UtilityClassException;

Utilities for working with generic types.
/** * Utilities for working with generic types. */
@SuppressWarnings("rawtypes") public class GenericTypes { private static final TypeVariable<Class<Map>> KEY; private static final TypeVariable<Class<Map>> VALUE; static { TypeVariable<Class<Map>>[] mapParams = Map.class.getTypeParameters(); KEY = mapParams[0]; VALUE = mapParams[1]; } private GenericTypes() { throw new UtilityClassException(); }
Returns the erased class for the given type.

Example: if type is List<String>, returns List.class

parameter
Params:
  • type – the type
Returns:the erased class
/** * Returns the erased class for the given type. * * <p> * Example: if type is <code>List&lt;String&gt;</code>, returns * <code>List.class</code> * </p> * parameter * * @param type the type * @return the erased class */
public static Class<?> getErasedType(Type type) { return GenericTypeReflector.erase(type); }
Params:
  • type – the type
  • parameterizedSupertype – the parameterized supertype
See Also:
Returns:the first parameter type
/** * Same as {@link #findGenericParameter(Type, Class, int)} with n = 0. * * @param type the type * @param parameterizedSupertype the parameterized supertype * @return the first parameter type * @see #findGenericParameter(Type, Class, int) */
public static Optional<Type> findGenericParameter(Type type, Class<?> parameterizedSupertype) { return findGenericParameter(type, parameterizedSupertype, 0); }
For the given type which extends parameterizedSupertype, returns the nth generic parameter for the parameterized supertype, if concretely expressed.

Example:

  • if type is ArrayList<String>, parameterizedSuperType is List.class, and n is 0, returns Optional.of(String.class).
  • if type is Map<String, Integer>, parameterizedSuperType is Map.class, and n is 1, returns Optional.of(Integer.class).
  • if type is ArrayList.class (raw), parameterizedSuperType is List.class, and n is 0, returns Optional.empty().
Params:
  • type – the subtype of parameterizedSupertype
  • parameterizedSupertype – the parameterized supertype from which we want the generic parameter
  • n – the index in Foo<X, Y, Z, ...>
Throws:
Returns:the parameter on the supertype, if it is concretely defined.
/** * For the given type which extends parameterizedSupertype, returns the * nth generic parameter for the parameterized supertype, if concretely * expressed. * * <p> * Example: * </p> * <ul> * <li>if {@code type} is {@code ArrayList<String>}, * {@code parameterizedSuperType} is {@code List.class}, * and {@code n} is {@code 0}, * returns {@code Optional.of(String.class)}.</li> * * <li>if {@code type} is {@code Map<String, Integer>}, * {@code parameterizedSuperType} is {@code Map.class}, * and {@code n} is {@code 1}, * returns {@code Optional.of(Integer.class)}.</li> * * <li>if {@code type} is {@code ArrayList.class} (raw), * {@code parameterizedSuperType} is {@code List.class}, * and {@code n} is {@code 0}, * returns {@code Optional.empty()}.</li> * </ul> * * @param type the subtype of parameterizedSupertype * @param parameterizedSupertype the parameterized supertype from which we want the generic parameter * @param n the index in {@code Foo<X, Y, Z, ...>} * @return the parameter on the supertype, if it is concretely defined. * @throws ArrayIndexOutOfBoundsException if n &gt; the number of type variables the type has */
public static Optional<Type> findGenericParameter(Type type, Class<?> parameterizedSupertype, int n) { return Optional.ofNullable(GenericTypeReflector.getTypeParameter(type, parameterizedSupertype.getTypeParameters()[n])); }
Resolves the type parameter in the context of contextType. For example, if type is List.class.getMethod("get", int.class).getGenericReturnType(), and contextType is List<String>, this method returns String.class
Params:
  • type – the type to be resolved in the scope of contextType
  • contextType – the context type in which type is interpreted to resolve the type.
Returns:the resolved type.
/** * Resolves the {@code type} parameter in the context of {@code contextType}. For example, if * {@code type} is {@code List.class.getMethod("get", int.class).getGenericReturnType()}, and * {@code contextType} is {@code List<String>}, this method returns {@code String.class} * @param type the type to be resolved in the scope of <code>contextType</code> * @param contextType the context type in which <code>type</code> is interpreted to resolve the type. * @return the resolved type. */
public static Type resolveType(Type type, Type contextType) { return GenericTypeReflector.resolveType(type, contextType); }
Params:
  • type – a type
Returns:whether the given Type is an Array type.
/** * @param type a type * @return whether the given {@code Type} is an Array type. */
public static boolean isArray(Type type) { return type instanceof Class<?> && ((Class<?>) type).isArray(); }
Given a subtype of Map<K,V>, returns the corresponding map entry type Map.Entry<K,V>.
Params:
  • mapType – the map subtype
Returns:the map entry type
/** * Given a subtype of {@code Map<K,V>}, returns the corresponding map entry type {@code Map.Entry<K,V>}. * @param mapType the map subtype * @return the map entry type */
public static Type resolveMapEntryType(Type mapType) { Type keyType = resolveType(KEY, mapType); Type valueType = resolveType(VALUE, mapType); return resolveMapEntryType(keyType, valueType); }
Given a key and value type, returns the map entry type Map.Entry<keyType,valueType>.
Params:
  • keyType – the key type
  • valueType – the value type
Returns:the map entry type
/** * Given a key and value type, returns the map entry type {@code Map.Entry<keyType,valueType>}. * @param keyType the key type * @param valueType the value type * @return the map entry type */
public static Type resolveMapEntryType(Type keyType, Type valueType) { return TypeFactory.parameterizedClass(Map.Entry.class, keyType, valueType); }
Creates a type of class clazz with arguments as type arguments.

For example: parameterizedClass(Map.class, Integer.class, String.class) returns the type Map<Integer, String>.

Params:
  • clazz – Type class of the type to create
  • arguments – Type arguments for the variables of clazz, or null if these are not known.
Returns:A ParameterizedType, or simply clazz if arguments is null or empty.
/** * Creates a type of class {@code clazz} with {@code arguments} as type arguments. * <p> * For example: {@code parameterizedClass(Map.class, Integer.class, String.class)} * returns the type {@code Map<Integer, String>}. * * @param clazz Type class of the type to create * @param arguments Type arguments for the variables of {@code clazz}, or null if these are not * known. * @return A {@link ParameterizedType}, or simply {@code clazz} if {@code arguments} is * {@code null} or empty. */
public static Type parameterizeClass(Class<?> clazz, Type... arguments) { return TypeFactory.parameterizedClass(clazz, arguments); } }