/******************************************************************************* * Copyright (c) 2010-present Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Stuart McCulloch (Sonatype, Inc.) - initial API and implementation *******************************************************************************/ package org.eclipse.sisu.plexus; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; /** * Utility methods for dealing with generic type arguments. */ public final class TypeArguments { // ---------------------------------------------------------------------- // Constants // ---------------------------------------------------------------------- private static final Type OBJECT_TYPE = Object.class; private static final Type[] NO_TYPES = {}; // ---------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------- private TypeArguments() { // static utility class, not allowed to create instances } // ---------------------------------------------------------------------- // Utility methods // ---------------------------------------------------------------------- /** * Get all type arguments from a generic type, for example {@code [Foo,Bar]} from {@code Map<Foo,Bar>}. * * @param type The generic type * @return Array of type arguments */ public static Type[] get( final Type type ) { if ( type instanceof ParameterizedType ) { final Type[] argumentTypes = ( (ParameterizedType) type ).getActualTypeArguments(); for ( int i = 0; i < argumentTypes.length; i++ ) { argumentTypes[i] = expand( argumentTypes[i] ); } return argumentTypes; } if ( type instanceof GenericArrayType ) { return new Type[] { expand( ( (GenericArrayType) type ).getGenericComponentType() ) }; } return NO_TYPES; } /** * Get an indexed type argument from a generic type, for example {@code Bar} from {@code Map<Foo,Bar>}. * * @param type The generic type * @param index The argument index * @return Indexed type argument; {@code Object.class} if the given type is a raw class */ public static Type get( final Type type, final int index ) { if ( type instanceof ParameterizedType ) { return expand( ( (ParameterizedType) type ).getActualTypeArguments()[index] ); } if ( type instanceof GenericArrayType ) { if ( 0 == index ) { return expand( ( (GenericArrayType) type ).getGenericComponentType() ); } throw new ArrayIndexOutOfBoundsException( index ); } return OBJECT_TYPE; } // ---------------------------------------------------------------------- // Implementation methods // ---------------------------------------------------------------------- /** * Expands wild-card types where possible, for example {@code Bar} from {@code ? extends Bar}. * * @param type The generic type * @return Widened type that is still assignment-compatible with the original. */ private static Type expand( final Type type ) { if ( type instanceof WildcardType ) { return ( (WildcardType) type ).getUpperBounds()[0]; } if ( type instanceof TypeVariable<?> ) { return ( (TypeVariable<?>) type ).getBounds()[0]; } return type; } }