Bug 498757: extract re-usable TypeArguments utility methods
diff --git a/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/CompositeBeanHelper.java b/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/CompositeBeanHelper.java
index 7890527..4c9b963 100644
--- a/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/CompositeBeanHelper.java
+++ b/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/CompositeBeanHelper.java
@@ -11,14 +11,10 @@
 package org.eclipse.sisu.plexus;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
@@ -40,12 +36,6 @@
 public final class CompositeBeanHelper
 {
     // ----------------------------------------------------------------------
-    // Constants
-    // ----------------------------------------------------------------------
-
-    private static final Type[] NO_TYPES = {};
-
-    // ----------------------------------------------------------------------
     // Implementation fields
     // ----------------------------------------------------------------------
 
@@ -264,7 +254,7 @@
         final ConfigurationConverter converter = lookup.lookupConverterForType( rawPropertyType );
         if ( !( genericPropertyType instanceof Class<?> ) && converter instanceof ParameterizedConfigurationConverter )
         {
-            final Type[] propertyTypeArgs = getTypeArguments( genericPropertyType );
+            final Type[] propertyTypeArgs = TypeArguments.get( genericPropertyType );
             return ( (ParameterizedConfigurationConverter) converter ).fromConfiguration( lookup, configuration,
                                                                                           rawPropertyType,
                                                                                           propertyTypeArgs, beanType,
@@ -274,37 +264,6 @@
                                             listener );
     }
 
-    private static Type[] getTypeArguments( final Type type )
-    {
-        if ( type instanceof ParameterizedType )
-        {
-            final Type[] typeArguments = ( (ParameterizedType) type ).getActualTypeArguments();
-            for ( int i = 0; i < typeArguments.length; i++ )
-            {
-                typeArguments[i] = expandType( typeArguments[i] );
-            }
-            return typeArguments;
-        }
-        if ( type instanceof GenericArrayType )
-        {
-            return new Type[] { expandType( ( (GenericArrayType) type ).getGenericComponentType() ) };
-        }
-        return NO_TYPES;
-    }
-
-    private static Type expandType( final Type type )
-    {
-        if ( type instanceof WildcardType )
-        {
-            return ( (WildcardType) type ).getUpperBounds()[0];
-        }
-        if ( type instanceof TypeVariable<?> )
-        {
-            return ( (TypeVariable<?>) type ).getBounds()[0];
-        }
-        return type;
-    }
-
     private static Method findMethod( final Class<?> beanType, final Type[] paramTypeHolder, final String methodName )
     {
         for ( final Method m : beanType.getMethods() )
diff --git a/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/TypeArguments.java b/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/TypeArguments.java
new file mode 100644
index 0000000..e37609d
--- /dev/null
+++ b/org.eclipse.sisu.plexus/src/org/eclipse/sisu/plexus/TypeArguments.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * 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;
+    }
+}