You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by si...@apache.org on 2012/02/06 20:56:43 UTC

svn commit: r1241133 [1/2] - in /commons/sandbox/beanutils2/trunk: ./ src/main/java/org/apache/commons/beanutils2/type/ src/test/java/org/apache/commons/beanutils2/type/

Author: simonetripodi
Date: Mon Feb  6 19:56:42 2012
New Revision: 1241133

URL: http://svn.apache.org/viewvc?rev=1241133&view=rev
Log:
extracted, cleaned, polished and retailed the TypeLyteral framework from Google Guice, to better manipulate types handling

Added:
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java   (with props)
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java   (with props)
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java   (with props)
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTypeResolutionTest.java   (with props)
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypesTest.java   (with props)
Modified:
    commons/sandbox/beanutils2/trunk/pom.xml

Modified: commons/sandbox/beanutils2/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/pom.xml?rev=1241133&r1=1241132&r2=1241133&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/pom.xml (original)
+++ commons/sandbox/beanutils2/trunk/pom.xml Mon Feb  6 19:56:42 2012
@@ -91,6 +91,12 @@
       <version>4.10</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>11.0.1</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,29 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/** A type formed from other types, such as arrays, parameterized types or wildcard types */
+interface CompositeType
+{
+
+    /** Returns true if there are no type variables in this type. */
+    boolean isFullySpecified();
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/CompositeType.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,69 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.commons.beanutils2.type.MoreTypes.typeToString;
+
+import java.io.Serializable;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+
+final class GenericArrayTypeImpl
+    implements GenericArrayType, Serializable, CompositeType
+{
+
+    private static final long serialVersionUID = 0;
+
+    private final Type componentType;
+
+    public GenericArrayTypeImpl( Type componentType )
+    {
+        this.componentType = MoreTypes.canonicalize( componentType );
+    }
+
+    public Type getGenericComponentType()
+    {
+        return componentType;
+    }
+
+    public boolean isFullySpecified()
+    {
+        return MoreTypes.isFullySpecified( componentType );
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        return o instanceof GenericArrayType && MoreTypes.equals( this, (GenericArrayType) o );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return componentType.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return typeToString( componentType ) + "[]";
+    }
+
+}
\ No newline at end of file

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/GenericArrayTypeImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,362 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.commons.beanutils2.type.Objects.equal;
+import static org.apache.commons.beanutils2.internal.Assertions.checkArgument;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+/**
+ * Static methods for working with types that we aren't publishing in the public {@code Types} API.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+final class MoreTypes
+{
+
+    public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
+
+    private MoreTypes()
+    {
+    }
+
+    private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER =
+        new HashMap<TypeLiteral<?>, TypeLiteral<?>>();
+
+    static
+    {
+        register( boolean.class, Boolean.class );
+        register( byte.class, Byte.class );
+        register( short.class, Short.class );
+        register( int.class, Integer.class );
+        register( long.class, Long.class );
+        register( float.class, Float.class );
+        register( double.class, Double.class );
+        register( char.class, Character.class );
+        register( void.class, Void.class );
+    }
+
+    private static void register( Class<?> primitive, Class<?> wrapper )
+    {
+        PRIMITIVE_TO_WRAPPER.put( TypeLiteral.get( primitive ), TypeLiteral.get( wrapper ) );
+    }
+
+    /**
+     * Returns an type that's appropriate for use in a key.
+     * <p>
+     * If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a
+     * {@code com.google.inject.Provider} with the same type parameters.
+     * <p>
+     * If the type is a primitive, the corresponding wrapper type will be returned.
+     *
+     * @throws IllegalArgumentException if {@code type} contains a type variable
+     */
+    public static <T> TypeLiteral<T> canonicalizeForKey( TypeLiteral<T> typeLiteral )
+    {
+        Type type = typeLiteral.getType();
+        checkArgument( isFullySpecified( type ), "%s cannot be used as a key; It is not fully specified.", type );
+
+        @SuppressWarnings( "unchecked" )
+        TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get( typeLiteral );
+        return wrappedPrimitives != null ? wrappedPrimitives : typeLiteral;
+    }
+
+    /**
+     * Returns true if {@code type} is free from type variables.
+     */
+    static boolean isFullySpecified( Type type )
+    {
+        if ( type instanceof Class )
+        {
+            return true;
+
+        }
+        else if ( type instanceof CompositeType )
+        {
+            return ( (CompositeType) type ).isFullySpecified();
+
+        }
+        else if ( type instanceof TypeVariable )
+        {
+            return false;
+
+        }
+        else
+        {
+            return ( (CompositeType) canonicalize( type ) ).isFullySpecified();
+        }
+    }
+
+    /**
+     * Returns a type that is functionally equal but not necessarily equal according to {@link Object#equals(Object)
+     * Object.equals()}. The returned type is {@link Serializable}.
+     */
+    public static Type canonicalize( Type type )
+    {
+        if ( type instanceof Class )
+        {
+            Class<?> c = (Class<?>) type;
+            return c.isArray() ? new GenericArrayTypeImpl( canonicalize( c.getComponentType() ) ) : c;
+        }
+        else if ( type instanceof CompositeType )
+        {
+            return type;
+        }
+        else if ( type instanceof ParameterizedType )
+        {
+            ParameterizedType p = (ParameterizedType) type;
+            return new ParameterizedTypeImpl( p.getOwnerType(), p.getRawType(), p.getActualTypeArguments() );
+        }
+        else if ( type instanceof GenericArrayType )
+        {
+            GenericArrayType g = (GenericArrayType) type;
+            return new GenericArrayTypeImpl( g.getGenericComponentType() );
+        }
+        else if ( type instanceof WildcardType )
+        {
+            WildcardType w = (WildcardType) type;
+            return new WildcardTypeImpl( w.getUpperBounds(), w.getLowerBounds() );
+        }
+        // type is either serializable as-is or unsupported
+        return type;
+    }
+
+    public static Class<?> getRawType( Type type )
+    {
+        if ( type instanceof Class<?> )
+        {
+            // type is a normal class.
+            return (Class<?>) type;
+        }
+        else if ( type instanceof ParameterizedType )
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+
+            // I'm not exactly sure why getRawType() returns Type instead of Class.
+            // Neal isn't either but suspects some pathological case related
+            // to nested classes exists.
+            Type rawType = parameterizedType.getRawType();
+            checkArgument( rawType instanceof Class, "Expected a Class, but <%s> is of type %s", type,
+                           type.getClass().getName() );
+            return (Class<?>) rawType;
+        }
+        else if ( type instanceof GenericArrayType )
+        {
+            Type componentType = ( (GenericArrayType) type ).getGenericComponentType();
+            return Array.newInstance( getRawType( componentType ), 0 ).getClass();
+        }
+        else if ( type instanceof TypeVariable )
+        {
+            // we could use the variable's bounds, but that'll won't work if there are multiple.
+            // having a raw type that's more general than necessary is okay
+            return Object.class;
+        }
+
+        throw new IllegalArgumentException( "Expected a Class, ParameterizedType, or GenericArrayType, but <" + type
+            + "> is of type " + type.getClass().getName() );
+    }
+
+    /**
+     * Returns true if {@code a} and {@code b} are equal.
+     */
+    public static boolean equals( Type a, Type b )
+    {
+        if ( a == b )
+        {
+            // also handles (a == null && b == null)
+            return true;
+        }
+        else if ( a instanceof Class )
+        {
+            // Class already specifies equals().
+            return a.equals( b );
+        }
+        else if ( a instanceof ParameterizedType )
+        {
+            if ( !( b instanceof ParameterizedType ) )
+            {
+                return false;
+            }
+
+            // TODO: save a .clone() call
+            ParameterizedType pa = (ParameterizedType) a;
+            ParameterizedType pb = (ParameterizedType) b;
+            return equal( pa.getOwnerType(), pb.getOwnerType() ) && pa.getRawType().equals( pb.getRawType() )
+                && Arrays.equals( pa.getActualTypeArguments(), pb.getActualTypeArguments() );
+        }
+        else if ( a instanceof GenericArrayType )
+        {
+            if ( !( b instanceof GenericArrayType ) )
+            {
+                return false;
+            }
+
+            GenericArrayType ga = (GenericArrayType) a;
+            GenericArrayType gb = (GenericArrayType) b;
+            return equals( ga.getGenericComponentType(), gb.getGenericComponentType() );
+        }
+        else if ( a instanceof WildcardType )
+        {
+            if ( !( b instanceof WildcardType ) )
+            {
+                return false;
+            }
+
+            WildcardType wa = (WildcardType) a;
+            WildcardType wb = (WildcardType) b;
+            return Arrays.equals( wa.getUpperBounds(), wb.getUpperBounds() )
+                && Arrays.equals( wa.getLowerBounds(), wb.getLowerBounds() );
+        }
+        else if ( a instanceof TypeVariable )
+        {
+            if ( !( b instanceof TypeVariable ) )
+            {
+                return false;
+            }
+            TypeVariable<?> va = (TypeVariable<?>) a;
+            TypeVariable<?> vb = (TypeVariable<?>) b;
+            return va.getGenericDeclaration() == vb.getGenericDeclaration() && va.getName().equals( vb.getName() );
+        }
+
+        // This isn't a type we support. Could be a generic array type, wildcard type, etc.
+        return false;
+    }
+
+    static int hashCodeOrZero( Object o )
+    {
+        return o != null ? o.hashCode() : 0;
+    }
+
+    public static String typeToString( Type type )
+    {
+        return type instanceof Class ? ( (Class<?>) type ).getName() : type.toString();
+    }
+
+    /**
+     * Returns the generic supertype for {@code supertype}. For example, given a class {@code IntegerSet}, the result
+     * for when supertype is {@code Set.class} is {@code Set<Integer>} and the result when the supertype is
+     * {@code Collection.class} is {@code Collection<Integer>}.
+     */
+    public static Type getGenericSupertype( Type type, Class<?> rawType, Class<?> toResolve )
+    {
+        if ( toResolve == rawType )
+        {
+            return type;
+        }
+
+        // we skip searching through interfaces if unknown is an interface
+        if ( toResolve.isInterface() )
+        {
+            Class<?>[] interfaces = rawType.getInterfaces();
+            for ( int i = 0, length = interfaces.length; i < length; i++ )
+            {
+                if ( interfaces[i] == toResolve )
+                {
+                    return rawType.getGenericInterfaces()[i];
+                }
+                else if ( toResolve.isAssignableFrom( interfaces[i] ) )
+                {
+                    return getGenericSupertype( rawType.getGenericInterfaces()[i], interfaces[i], toResolve );
+                }
+            }
+        }
+
+        // check our supertypes
+        if ( !rawType.isInterface() )
+        {
+            while ( rawType != Object.class )
+            {
+                Class<?> rawSupertype = rawType.getSuperclass();
+                if ( rawSupertype == toResolve )
+                {
+                    return rawType.getGenericSuperclass();
+                }
+                else if ( toResolve.isAssignableFrom( rawSupertype ) )
+                {
+                    return getGenericSupertype( rawType.getGenericSuperclass(), rawSupertype, toResolve );
+                }
+                rawType = rawSupertype;
+            }
+        }
+
+        // we can't resolve this further
+        return toResolve;
+    }
+
+    public static Type resolveTypeVariable( Type type, Class<?> rawType, TypeVariable<?> unknown )
+    {
+        Class<?> declaredByRaw = declaringClassOf( unknown );
+
+        // we can't reduce this further
+        if ( declaredByRaw == null )
+        {
+            return unknown;
+        }
+
+        Type declaredBy = getGenericSupertype( type, rawType, declaredByRaw );
+        if ( declaredBy instanceof ParameterizedType )
+        {
+            int index = indexOf( declaredByRaw.getTypeParameters(), unknown );
+            return ( (ParameterizedType) declaredBy ).getActualTypeArguments()[index];
+        }
+
+        return unknown;
+    }
+
+    private static int indexOf( Object[] array, Object toFind )
+    {
+        for ( int i = 0; i < array.length; i++ )
+        {
+            if ( toFind.equals( array[i] ) )
+            {
+                return i;
+            }
+        }
+        throw new NoSuchElementException();
+    }
+
+    /**
+     * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by a class.
+     */
+    private static Class<?> declaringClassOf( TypeVariable<?> typeVariable )
+    {
+        GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+        return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null;
+    }
+
+    static void checkNotPrimitive( Type type, String use )
+    {
+        checkArgument( !( type instanceof Class<?> ) || !( (Class<?>) type ).isPrimitive(),
+                       "Primitive types are not allowed in %s: %s", use, type );
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/MoreTypes.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,48 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+final class Objects
+{
+
+    private Objects()
+    {
+        // do nothing
+    }
+
+    /**
+     * Determines whether two possibly-null objects are equal. Returns:
+     *
+     * <ul>
+     * <li>{@code true} if {@code a} and {@code b} are both null.
+     * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
+     *     equal according to {@link Object#equals(Object)}.
+     * <li>{@code false} in all other situations.
+     * </ul>
+     *
+     * <p>This assumes that any non-null objects passed to this function conform
+     * to the {@code equals()} contract.
+     */
+    public static boolean equal( Object a, Object b )
+    {
+        return a == b || ( a != null && a.equals( b ) );
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Objects.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,138 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.commons.beanutils2.type.MoreTypes.canonicalize;
+import static org.apache.commons.beanutils2.type.MoreTypes.checkNotPrimitive;
+import static org.apache.commons.beanutils2.type.MoreTypes.hashCodeOrZero;
+import static org.apache.commons.beanutils2.type.MoreTypes.typeToString;
+import static org.apache.commons.beanutils2.internal.Assertions.checkArgument;
+import static org.apache.commons.beanutils2.internal.Assertions.checkNotNull;
+
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+final class ParameterizedTypeImpl
+    implements ParameterizedType, Serializable, CompositeType
+{
+
+    private static final long serialVersionUID = 0;
+
+    private final Type ownerType;
+
+    private final Type rawType;
+
+    private final Type[] typeArguments;
+
+    public ParameterizedTypeImpl( Type ownerType, Type rawType, Type... typeArguments )
+    {
+        // require an owner type if the raw type needs it
+        if ( rawType instanceof Class<?> )
+        {
+            Class<?> rawTypeAsClass = (Class<?>) rawType;
+            checkArgument( ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
+                           "No owner type for enclosed %s", rawType );
+            checkArgument( ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
+                           "Owner type for unenclosed %s", rawType );
+        }
+
+        this.ownerType = ownerType == null ? null : canonicalize( ownerType );
+        this.rawType = canonicalize( rawType );
+        this.typeArguments = typeArguments.clone();
+        for ( int t = 0; t < this.typeArguments.length; t++ )
+        {
+            checkNotNull( this.typeArguments[t], "type parameter" );
+            checkNotPrimitive( this.typeArguments[t], "type parameters" );
+            this.typeArguments[t] = canonicalize( this.typeArguments[t] );
+        }
+    }
+
+    public Type[] getActualTypeArguments()
+    {
+        return typeArguments.clone();
+    }
+
+    public Type getRawType()
+    {
+        return rawType;
+    }
+
+    public Type getOwnerType()
+    {
+        return ownerType;
+    }
+
+    public boolean isFullySpecified()
+    {
+        if ( ownerType != null && !MoreTypes.isFullySpecified( ownerType ) )
+        {
+            return false;
+        }
+
+        if ( !MoreTypes.isFullySpecified( rawType ) )
+        {
+            return false;
+        }
+
+        for ( Type type : typeArguments )
+        {
+            if ( !MoreTypes.isFullySpecified( type ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean equals( Object other )
+    {
+        return other instanceof ParameterizedType && MoreTypes.equals( this, (ParameterizedType) other );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Arrays.hashCode( typeArguments ) ^ rawType.hashCode() ^ hashCodeOrZero( ownerType );
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder stringBuilder = new StringBuilder( 30 * ( typeArguments.length + 1 ) );
+        stringBuilder.append( typeToString( rawType ) );
+
+        if ( typeArguments.length == 0 )
+        {
+            return stringBuilder.toString();
+        }
+
+        stringBuilder.append( "<" ).append( typeToString( typeArguments[0] ) );
+        for ( int i = 1; i < typeArguments.length; i++ )
+        {
+            stringBuilder.append( ", " ).append( typeToString( typeArguments[i] ) );
+        }
+        return stringBuilder.append( ">" ).toString();
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/ParameterizedTypeImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,384 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableList;
+import static org.apache.commons.beanutils2.type.MoreTypes.canonicalize;
+import static org.apache.commons.beanutils2.type.MoreTypes.getGenericSupertype;
+import static org.apache.commons.beanutils2.type.MoreTypes.resolveTypeVariable;
+import static org.apache.commons.beanutils2.type.MoreTypes.typeToString;
+import static org.apache.commons.beanutils2.internal.Assertions.checkArgument;
+import static org.apache.commons.beanutils2.internal.Assertions.checkNotNull;
+import static org.apache.commons.beanutils2.type.Types.arrayOf;
+import static org.apache.commons.beanutils2.type.Types.newParameterizedTypeWithOwner;
+import static org.apache.commons.beanutils2.type.Types.subtypeOf;
+import static org.apache.commons.beanutils2.type.Types.supertypeOf;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+/**
+ * Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types, so this class does.
+ * Forces clients to create a subclass of this class which enables retrieval the type information even at runtime.
+ * <p>
+ * For example, to create a type literal for {@code List<String>}, you can create an empty anonymous inner class:
+ * <p>
+ * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() ;}
+ * <p>
+ * Along with modeling generic types, this class can resolve type parameters. For example, to figure out what type
+ * {@code keySet()} returns on a {@code Map<Integer, String>}, use this code:
+ *
+ * <pre>
+ * {@code
+ *
+ *   TypeLiteral<Map<Integer, String>> mapType
+ *       = new TypeLiteral<Map<Integer, String>>() {};
+ *   TypeLiteral<?> keySetType
+ *       = mapType.getReturnType(Map.class.getMethod("keySet"));
+ *   System.out.println(keySetType); // prints "Set<Integer>"}
+ * </pre>
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+public class TypeLiteral<T>
+{
+
+    final Class<? super T> rawType;
+
+    final Type type;
+
+    final int hashCode;
+
+    /**
+     * Constructs a new type literal. Derives represented class from type parameter.
+     * <p>
+     * Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type
+     * hierarchy so we can reconstitute it at runtime despite erasure.
+     */
+    @SuppressWarnings( "unchecked" )
+    protected TypeLiteral()
+    {
+        this.type = getSuperclassTypeParameter( getClass() );
+        this.rawType = (Class<? super T>) MoreTypes.getRawType( type );
+        this.hashCode = type.hashCode();
+    }
+
+    /**
+     * Unsafe. Constructs a type literal manually.
+     */
+    @SuppressWarnings( "unchecked" )
+    TypeLiteral( Type type )
+    {
+        this.type = canonicalize( checkNotNull( type, "type" ) );
+        this.rawType = (Class<? super T>) MoreTypes.getRawType( this.type );
+        this.hashCode = this.type.hashCode();
+    }
+
+    /**
+     * Returns the type from super class's type parameter in {@link MoreTypes#canonicalize(Type) canonical form}.
+     */
+    static Type getSuperclassTypeParameter( Class<?> subclass )
+    {
+        Type superclass = subclass.getGenericSuperclass();
+        if ( superclass instanceof Class )
+        {
+            throw new RuntimeException( "Missing type parameter." );
+        }
+        ParameterizedType parameterized = (ParameterizedType) superclass;
+        return canonicalize( parameterized.getActualTypeArguments()[0] );
+    }
+
+    /**
+     * Gets type literal from super class's type parameter.
+     */
+    static TypeLiteral<?> fromSuperclassTypeParameter( Class<?> subclass )
+    {
+        return new TypeLiteral<Object>( getSuperclassTypeParameter( subclass ) );
+    }
+
+    /**
+     * Returns the raw (non-generic) type for this type.
+     *
+     * @since 2.0
+     */
+    public final Class<? super T> getRawType()
+    {
+        return rawType;
+    }
+
+    /**
+     * Gets underlying {@code Type} instance.
+     */
+    public final Type getType()
+    {
+        return type;
+    }
+
+    @Override
+    public final int hashCode()
+    {
+        return this.hashCode;
+    }
+
+    @Override
+    public final boolean equals( Object o )
+    {
+        return o instanceof TypeLiteral<?> && MoreTypes.equals( type, ( (TypeLiteral<?>) o ).type );
+    }
+
+    @Override
+    public final String toString()
+    {
+        return typeToString( type );
+    }
+
+    /**
+     * Gets type literal for the given {@code Type} instance.
+     */
+    public static TypeLiteral<?> get( Type type )
+    {
+        return new TypeLiteral<Object>( type );
+    }
+
+    /**
+     * Gets type literal for the given {@code Class} instance.
+     */
+    public static <T> TypeLiteral<T> get( Class<T> type )
+    {
+        return new TypeLiteral<T>( type );
+    }
+
+    /** Returns an immutable list of the resolved types. */
+    private List<TypeLiteral<?>> resolveAll( Type[] types )
+    {
+        TypeLiteral<?>[] result = new TypeLiteral<?>[types.length];
+        for ( int t = 0; t < types.length; t++ )
+        {
+            result[t] = resolve( types[t] );
+        }
+        return unmodifiableList( asList( result ) );
+    }
+
+    /**
+     * Resolves known type parameters in {@code toResolve} and returns the result.
+     */
+    TypeLiteral<?> resolve( Type toResolve )
+    {
+        return TypeLiteral.get( resolveType( toResolve ) );
+    }
+
+    Type resolveType( Type toResolve )
+    {
+        // this implementation is made a little more complicated in an attempt to avoid object-creation
+        while ( true )
+        {
+            if ( toResolve instanceof TypeVariable )
+            {
+                TypeVariable<?> original = (TypeVariable<?>) toResolve;
+                toResolve = resolveTypeVariable( type, rawType, original );
+                if ( toResolve == original )
+                {
+                    return toResolve;
+                }
+
+            }
+            else if ( toResolve instanceof GenericArrayType )
+            {
+                GenericArrayType original = (GenericArrayType) toResolve;
+                Type componentType = original.getGenericComponentType();
+                Type newComponentType = resolveType( componentType );
+                return componentType == newComponentType ? original : arrayOf( newComponentType );
+
+            }
+            else if ( toResolve instanceof ParameterizedType )
+            {
+                ParameterizedType original = (ParameterizedType) toResolve;
+                Type ownerType = original.getOwnerType();
+                Type newOwnerType = resolveType( ownerType );
+                boolean changed = newOwnerType != ownerType;
+
+                Type[] args = original.getActualTypeArguments();
+                for ( int t = 0, length = args.length; t < length; t++ )
+                {
+                    Type resolvedTypeArgument = resolveType( args[t] );
+                    if ( resolvedTypeArgument != args[t] )
+                    {
+                        if ( !changed )
+                        {
+                            args = args.clone();
+                            changed = true;
+                        }
+                        args[t] = resolvedTypeArgument;
+                    }
+                }
+
+                return changed ? newParameterizedTypeWithOwner( newOwnerType, original.getRawType(), args )
+                                : original;
+
+            }
+            else if ( toResolve instanceof WildcardType )
+            {
+                WildcardType original = (WildcardType) toResolve;
+                Type[] originalLowerBound = original.getLowerBounds();
+                Type[] originalUpperBound = original.getUpperBounds();
+
+                if ( originalLowerBound.length == 1 )
+                {
+                    Type lowerBound = resolveType( originalLowerBound[0] );
+                    if ( lowerBound != originalLowerBound[0] )
+                    {
+                        return supertypeOf( lowerBound );
+                    }
+                }
+                else if ( originalUpperBound.length == 1 )
+                {
+                    Type upperBound = resolveType( originalUpperBound[0] );
+                    if ( upperBound != originalUpperBound[0] )
+                    {
+                        return subtypeOf( upperBound );
+                    }
+                }
+                return original;
+
+            }
+            else
+            {
+                return toResolve;
+            }
+        }
+    }
+
+    /**
+     * Returns the generic form of {@code supertype}. For example, if this is {@code ArrayList<String>}, this returns
+     * {@code Iterable<String>} given the input {@code Iterable.class}.
+     *
+     * @param supertype a superclass of, or interface implemented by, this.
+     * @since 2.0
+     */
+    public TypeLiteral<?> getSupertype( Class<?> supertype )
+    {
+        checkArgument( supertype.isAssignableFrom( rawType ), "%s is not a supertype of %s", supertype, this.type );
+        return resolve( getGenericSupertype( type, rawType, supertype ) );
+    }
+
+    /**
+     * Returns the resolved generic type of {@code field}.
+     *
+     * @param field a field defined by this or any superclass.
+     * @since 2.0
+     */
+    public TypeLiteral<?> getFieldType( Field field )
+    {
+        checkArgument( field.getDeclaringClass().isAssignableFrom( rawType ), "%s is not defined by a supertype of %s",
+                       field, type );
+        return resolve( field.getGenericType() );
+    }
+
+    /**
+     * Returns the resolved generic parameter types of {@code methodOrConstructor}.
+     *
+     * @param methodOrConstructor a method or constructor defined by this or any supertype.
+     * @since 2.0
+     */
+    public List<TypeLiteral<?>> getParameterTypes( Member methodOrConstructor )
+    {
+        Type[] genericParameterTypes;
+
+        if ( methodOrConstructor instanceof Method )
+        {
+            Method method = (Method) methodOrConstructor;
+            checkArgument( method.getDeclaringClass().isAssignableFrom( rawType ),
+                           "%s is not defined by a supertype of %s", method, type );
+            genericParameterTypes = method.getGenericParameterTypes();
+
+        }
+        else if ( methodOrConstructor instanceof Constructor )
+        {
+            Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
+            checkArgument( constructor.getDeclaringClass().isAssignableFrom( rawType ),
+                           "%s does not construct a supertype of %s", constructor, type );
+            genericParameterTypes = constructor.getGenericParameterTypes();
+
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Not a method or a constructor: " + methodOrConstructor );
+        }
+
+        return resolveAll( genericParameterTypes );
+    }
+
+    /**
+     * Returns the resolved generic exception types thrown by {@code constructor}.
+     *
+     * @param methodOrConstructor a method or constructor defined by this or any supertype.
+     * @since 2.0
+     */
+    public List<TypeLiteral<?>> getExceptionTypes( Member methodOrConstructor )
+    {
+        Type[] genericExceptionTypes;
+
+        if ( methodOrConstructor instanceof Method )
+        {
+            Method method = (Method) methodOrConstructor;
+            checkArgument( method.getDeclaringClass().isAssignableFrom( rawType ),
+                           "%s is not defined by a supertype of %s", method, type );
+            genericExceptionTypes = method.getGenericExceptionTypes();
+
+        }
+        else if ( methodOrConstructor instanceof Constructor )
+        {
+            Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
+            checkArgument( constructor.getDeclaringClass().isAssignableFrom( rawType ),
+                           "%s does not construct a supertype of %s", constructor, type );
+            genericExceptionTypes = constructor.getGenericExceptionTypes();
+
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Not a method or a constructor: " + methodOrConstructor );
+        }
+
+        return resolveAll( genericExceptionTypes );
+    }
+
+    /**
+     * Returns the resolved generic return type of {@code method}.
+     *
+     * @param method a method defined by this or any supertype.
+     * @since 2.0
+     */
+    public TypeLiteral<?> getReturnType( Method method )
+    {
+        checkArgument( method.getDeclaringClass().isAssignableFrom( rawType ),
+                       "%s is not defined by a supertype of %s", method, type );
+        return resolve( method.getGenericReturnType() );
+    }
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/TypeLiteral.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,125 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Static methods for working with types.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ * @since 2.0
+ */
+final class Types
+{
+    private Types()
+    {
+    }
+
+    /**
+     * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. The returned type does not
+     * have an owner type.
+     *
+     * @return a {@link java.io.Serializable serializable} parameterized type.
+     */
+    public static ParameterizedType newParameterizedType( Type rawType, Type... typeArguments )
+    {
+        return newParameterizedTypeWithOwner( null, rawType, typeArguments );
+    }
+
+    /**
+     * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType} and enclosed by
+     * {@code ownerType}.
+     *
+     * @return a {@link java.io.Serializable serializable} parameterized type.
+     */
+    public static ParameterizedType newParameterizedTypeWithOwner( Type ownerType, Type rawType, Type... typeArguments )
+    {
+        return new ParameterizedTypeImpl( ownerType, rawType, typeArguments );
+    }
+
+    /**
+     * Returns an array type whose elements are all instances of {@code componentType}.
+     *
+     * @return a {@link java.io.Serializable serializable} generic array type.
+     */
+    public static GenericArrayType arrayOf( Type componentType )
+    {
+        return new GenericArrayTypeImpl( componentType );
+    }
+
+    /**
+     * Returns a type that represents an unknown type that extends {@code bound}. For example, if {@code bound} is
+     * {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If {@code bound} is {@code Object.class}
+     * , this returns {@code ?}, which is shorthand for {@code ? extends Object}.
+     */
+    public static WildcardType subtypeOf( Type bound )
+    {
+        return new WildcardTypeImpl( new Type[] { bound }, MoreTypes.EMPTY_TYPE_ARRAY );
+    }
+
+    /**
+     * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code bound} is
+     * {@code String.class}, this returns {@code ?
+     * super String}.
+     */
+    public static WildcardType supertypeOf( Type bound )
+    {
+        return new WildcardTypeImpl( new Type[] { Object.class }, new Type[] { bound } );
+    }
+
+    /**
+     * Returns a type modelling a {@link List} whose elements are of type {@code elementType}.
+     *
+     * @return a {@link java.io.Serializable serializable} parameterized type.
+     */
+    public static ParameterizedType listOf( Type elementType )
+    {
+        return newParameterizedType( List.class, elementType );
+    }
+
+    /**
+     * Returns a type modelling a {@link Set} whose elements are of type {@code elementType}.
+     *
+     * @return a {@link java.io.Serializable serializable} parameterized type.
+     */
+    public static ParameterizedType setOf( Type elementType )
+    {
+        return newParameterizedType( Set.class, elementType );
+    }
+
+    /**
+     * Returns a type modelling a {@link Map} whose keys are of type {@code keyType} and whose values are of type
+     * {@code valueType}.
+     *
+     * @return a {@link java.io.Serializable serializable} parameterized type.
+     */
+    public static ParameterizedType mapOf( Type keyType, Type valueType )
+    {
+        return newParameterizedType( Map.class, keyType, valueType );
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/Types.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,117 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.commons.beanutils2.type.MoreTypes.EMPTY_TYPE_ARRAY;
+import static org.apache.commons.beanutils2.type.MoreTypes.canonicalize;
+import static org.apache.commons.beanutils2.type.MoreTypes.checkNotPrimitive;
+import static org.apache.commons.beanutils2.type.MoreTypes.typeToString;
+import static org.apache.commons.beanutils2.internal.Assertions.checkArgument;
+import static org.apache.commons.beanutils2.internal.Assertions.checkNotNull;
+
+import java.io.Serializable;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+
+
+/**
+ * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only support what the Java 6
+ * language needs - at most one bound. If a lower bound is set, the upper bound must be Object.class.
+ */
+final class WildcardTypeImpl
+    implements WildcardType, Serializable, CompositeType
+{
+
+    private static final long serialVersionUID = 0;
+
+    private final Type upperBound;
+
+    private final Type lowerBound;
+
+    public WildcardTypeImpl( Type[] upperBounds, Type[] lowerBounds )
+    {
+        checkArgument( lowerBounds.length <= 1, "Must have at most one lower bound." );
+        checkArgument( upperBounds.length == 1, "Must have exactly one upper bound." );
+
+        if ( lowerBounds.length == 1 )
+        {
+            checkNotNull( lowerBounds[0], "lowerBound" );
+            checkNotPrimitive( lowerBounds[0], "wildcard bounds" );
+            checkArgument( upperBounds[0] == Object.class, "bounded both ways" );
+            this.lowerBound = canonicalize( lowerBounds[0] );
+            this.upperBound = Object.class;
+
+        }
+        else
+        {
+            checkNotNull( upperBounds[0], "upperBound" );
+            checkNotPrimitive( upperBounds[0], "wildcard bounds" );
+            this.lowerBound = null;
+            this.upperBound = canonicalize( upperBounds[0] );
+        }
+    }
+
+    public Type[] getUpperBounds()
+    {
+        return new Type[] { upperBound };
+    }
+
+    public Type[] getLowerBounds()
+    {
+        return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
+    }
+
+    public boolean isFullySpecified()
+    {
+        return MoreTypes.isFullySpecified( upperBound )
+            && ( lowerBound == null || MoreTypes.isFullySpecified( lowerBound ) );
+    }
+
+    @Override
+    public boolean equals( Object other )
+    {
+        return other instanceof WildcardType && MoreTypes.equals( this, (WildcardType) other );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
+        return ( lowerBound != null ? 31 + lowerBound.hashCode() : 1 ) ^ ( 31 + upperBound.hashCode() );
+    }
+
+    @Override
+    public String toString()
+    {
+        if ( lowerBound != null )
+        {
+            return "? super " + typeToString( lowerBound );
+        }
+        else if ( upperBound == Object.class )
+        {
+            return "?";
+        }
+        else
+        {
+            return "? extends " + typeToString( upperBound );
+        }
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/WildcardTypeImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,23 @@
+/**
+ * The {@code TypeLiteral} framework, extracted from Google Guice.
+ */
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/type/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java (added)
+++ commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,134 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import junit.framework.Assert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+public class Asserts
+{
+    private Asserts()
+    {
+    }
+
+    /**
+     * Fails unless {@code expected.equals(actual)}, {@code actual.equals(expected)} and their hash codes are equal.
+     * This is useful for testing the equals method itself.
+     */
+    public static void assertEqualsBothWays( Object expected, Object actual )
+    {
+        assertNotNull( expected );
+        assertNotNull( actual );
+        assertTrue( "expected.equals(actual)", expected.equals( actual ) );
+        assertTrue( "actual.equals(expected)", actual.equals( expected ) );
+        assertEquals( "hashCode", expected.hashCode(), actual.hashCode() );
+    }
+
+    /**
+     * Fails unless {@code text} includes all {@code substrings}, in order.
+     */
+    public static void assertContains( String text, String... substrings )
+    {
+        /*
+         * if[NO_AOP] // when we strip out bytecode manipulation, we lose the ability to generate some source lines. if
+         * (text.contains("(Unknown Source)")) { return; } end[NO_AOP]
+         */
+
+        int startingFrom = 0;
+        for ( String substring : substrings )
+        {
+            int index = text.indexOf( substring, startingFrom );
+            assertTrue( String.format( "Expected \"%s\" to contain substring \"%s\"", text, substring ),
+                        index >= startingFrom );
+            startingFrom = index + substring.length();
+        }
+
+        String lastSubstring = substrings[substrings.length - 1];
+        assertTrue( String.format( "Expected \"%s\" to contain substring \"%s\" only once),", text, lastSubstring ),
+                    text.indexOf( lastSubstring, startingFrom ) == -1 );
+    }
+
+    /**
+     * Fails unless {@code object} doesn't equal itself when reserialized.
+     */
+    public static void assertEqualWhenReserialized( Object object )
+        throws IOException
+    {
+        Object reserialized = reserialize( object );
+        assertEquals( object, reserialized );
+        assertEquals( object.hashCode(), reserialized.hashCode() );
+    }
+
+    /**
+     * Fails unless {@code object} has the same toString value when reserialized.
+     */
+    public static void assertSimilarWhenReserialized( Object object )
+        throws IOException
+    {
+        Object reserialized = reserialize( object );
+        assertEquals( object.toString(), reserialized.toString() );
+    }
+
+    public static <E> E reserialize( E original )
+        throws IOException
+    {
+        try
+        {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            new ObjectOutputStream( out ).writeObject( original );
+            ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+            @SuppressWarnings( "unchecked" )
+            // the reserialized type is assignable
+            E reserialized = (E) new ObjectInputStream( in ).readObject();
+            return reserialized;
+        }
+        catch ( ClassNotFoundException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+    public static void assertNotSerializable( Object object )
+        throws IOException
+    {
+        try
+        {
+            reserialize( object );
+            Assert.fail();
+        }
+        catch ( NotSerializableException expected )
+        {
+        }
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/Asserts.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java?rev=1241133&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java (added)
+++ commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java Mon Feb  6 19:56:42 2012
@@ -0,0 +1,271 @@
+package org.apache.commons.beanutils2.type;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.apache.commons.beanutils2.type.Asserts.assertEqualsBothWays;
+import static org.apache.commons.beanutils2.type.Asserts.assertNotSerializable;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.List;
+
+import org.junit.Test;
+import org.apache.commons.beanutils2.type.TypeLiteral;
+import org.apache.commons.beanutils2.type.Types;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * @author crazybob@google.com (Bob Lee)
+ */
+public class TypeLiteralTest
+{
+
+    @Test
+    public void testWithParameterizedType()
+    {
+        TypeLiteral<List<String>> a = new TypeLiteral<List<String>>()
+        {
+        };
+        TypeLiteral<List<String>> b = new TypeLiteral<List<String>>( Types.listOf( String.class ) )
+        {
+        };
+        assertEqualsBothWays( a, b );
+    }
+
+    @Test
+    public void testEquality()
+    {
+        TypeLiteral<List<String>> t1 = new TypeLiteral<List<String>>()
+        {
+        };
+        TypeLiteral<List<String>> t2 = new TypeLiteral<List<String>>()
+        {
+        };
+        TypeLiteral<List<Integer>> t3 = new TypeLiteral<List<Integer>>()
+        {
+        };
+        TypeLiteral<String> t4 = new TypeLiteral<String>()
+        {
+        };
+
+        assertEqualsBothWays( t1, t2 );
+
+        assertFalse( t2.equals( t3 ) );
+        assertFalse( t3.equals( t2 ) );
+
+        assertFalse( t2.equals( t4 ) );
+        assertFalse( t4.equals( t2 ) );
+
+        TypeLiteral<String> t5 = TypeLiteral.get( String.class );
+        assertEqualsBothWays( t4, t5 );
+    }
+
+    public List<? extends CharSequence> wildcardExtends;
+
+    @Test
+    public void testWithWildcardType()
+        throws NoSuchFieldException, IOException
+    {
+        TypeLiteral<?> a = TypeLiteral.get( getClass().getField( "wildcardExtends" ).getGenericType() );
+        TypeLiteral<?> b = TypeLiteral.get( Types.listOf( Types.subtypeOf( CharSequence.class ) ) );
+        TypeLiteral<?> c = new TypeLiteral<List<? extends CharSequence>>()
+        {
+        };
+        assertEqualsBothWays( a, b );
+        assertEqualsBothWays( b, c );
+        assertEquals( "java.util.List<? extends java.lang.CharSequence>", a.toString() );
+        assertEquals( "java.util.List<? extends java.lang.CharSequence>", b.toString() );
+        assertEquals( "java.util.List<? extends java.lang.CharSequence>", c.toString() );
+        assertNotSerializable( a );
+        assertNotSerializable( b );
+        assertNotSerializable( c );
+    }
+
+    @Test
+    public void testMissingTypeParameter()
+    {
+        try
+        {
+            new TypeLiteral()
+            {
+            };
+            fail();
+        }
+        catch ( RuntimeException e )
+        { /* expected */
+        }
+    }
+
+    @Test
+    public void testTypesInvolvingArraysForEquality()
+    {
+        TypeLiteral<String[]> stringArray = new TypeLiteral<String[]>()
+        {
+        };
+        assertEquals( stringArray, new TypeLiteral<String[]>()
+        {
+        } );
+
+        TypeLiteral<List<String[]>> listOfStringArray = new TypeLiteral<List<String[]>>()
+        {
+        };
+        assertEquals( listOfStringArray, new TypeLiteral<List<String[]>>()
+        {
+        } );
+    }
+
+    @Test
+    public void testEqualityOfGenericArrayAndClassArray()
+    {
+        TypeLiteral<String[]> arrayAsClass = TypeLiteral.get( String[].class );
+        TypeLiteral<String[]> arrayAsType = new TypeLiteral<String[]>()
+        {
+        };
+        assertEquals( arrayAsClass, arrayAsType );
+    }
+
+    @Test
+    public void testEqualityOfMultidimensionalGenericArrayAndClassArray()
+    {
+        TypeLiteral<String[][][]> arrayAsClass = TypeLiteral.get( String[][][].class );
+        TypeLiteral<String[][][]> arrayAsType = new TypeLiteral<String[][][]>()
+        {
+        };
+        assertEquals( arrayAsClass, arrayAsType );
+    }
+
+    @Test
+    public void testTypeLiteralsMustHaveRawTypes()
+    {
+        try
+        {
+            TypeLiteral.get( Types.subtypeOf( Runnable.class ) );
+            fail();
+        }
+        catch ( IllegalArgumentException expected )
+        {
+            Asserts.assertContains( expected.getMessage(), "Expected a Class, ParameterizedType, or "
+                + "GenericArrayType, but <? extends java.lang.Runnable> is of type "
+                + "org.apache.commons.beanutils2.type.WildcardTypeImpl" );
+        }
+    }
+
+    /**
+     * Unlike Key, TypeLiteral retains full type information and differentiates between {@code int.class} and
+     * {@code Integer.class}.
+     */
+    @Test
+    public void testDifferentiationBetweenWrappersAndPrimitives()
+    {
+        Class[] primitives =
+            new Class[] { boolean.class, byte.class, short.class, int.class, long.class, float.class, double.class,
+                char.class, void.class };
+        Class[] wrappers =
+            new Class[] { Boolean.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class,
+                Character.class, Void.class };
+
+        for ( int t = 0; t < primitives.length; t++ )
+        {
+            @SuppressWarnings( "unchecked" )
+            TypeLiteral primitiveTl = TypeLiteral.get( primitives[t] );
+            @SuppressWarnings( "unchecked" )
+            TypeLiteral wrapperTl = TypeLiteral.get( wrappers[t] );
+
+            assertFalse( primitiveTl.equals( wrapperTl ) );
+            assertEquals( primitives[t], primitiveTl.getType() );
+            assertEquals( wrappers[t], wrapperTl.getType() );
+            assertEquals( primitives[t], primitiveTl.getRawType() );
+            assertEquals( wrappers[t], wrapperTl.getRawType() );
+        }
+    }
+
+    @Test
+    public void testSerialization()
+        throws IOException
+    {
+        assertNotSerializable( new TypeLiteral<List<String>>()
+        {
+        } );
+    }
+
+    @Test
+    public void testTypeVariableWithNoBound()
+    {
+        TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters();
+
+        TypeLiteral<?> aTl = TypeLiteral.get( typeVariables[0] );
+        assertEquals( Object.class, aTl.getRawType() );
+        assertEquals( "A", aTl.toString() );
+        TypeVariable<?> aTv = (TypeVariable) aTl.getType();
+        assertEquals( HasTypeParameters.class, aTv.getGenericDeclaration() );
+        assertEquals( "A", aTv.getName() );
+        assertEquals( ImmutableList.<Type> of( Object.class ), ImmutableList.copyOf( aTv.getBounds() ) );
+        assertEquals( "A", aTv.toString() );
+        assertEqualsBothWays( aTl, TypeLiteral.get( HasTypeParameters.class.getTypeParameters()[0] ) );
+    }
+
+    @Test
+    public void testTypeVariablesWithSingleBound()
+    {
+        TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters();
+
+        TypeLiteral<?> cTl = TypeLiteral.get( typeVariables[2] );
+        assertEquals( Object.class, cTl.getRawType() );
+        assertEquals( "C", cTl.toString() );
+        TypeVariable<?> cTv = (TypeVariable) cTl.getType();
+        assertEquals( HasTypeParameters.class, cTv.getGenericDeclaration() );
+        assertEquals( "C", cTv.getName() );
+        assertEquals( ImmutableList.<Type> of( Runnable.class ), ImmutableList.copyOf( cTv.getBounds() ) );
+        assertEquals( "C", cTv.toString() );
+        assertEqualsBothWays( cTl, TypeLiteral.get( HasTypeParameters.class.getTypeParameters()[2] ) );
+    }
+
+    @Test
+    public void testTypeVariableWithMultipleBounds()
+    {
+        TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters();
+
+        TypeLiteral<?> bTl = TypeLiteral.get( typeVariables[1] );
+        assertEquals( Object.class, bTl.getRawType() );
+        assertEquals( "B", bTl.toString() );
+        TypeVariable<?> bTv = (TypeVariable) bTl.getType();
+        assertEquals( HasTypeParameters.class, bTv.getGenericDeclaration() );
+        assertEquals( "B", bTv.getName() );
+        assertEquals( ImmutableList.<Type> of( Types.listOf( typeVariables[0] ), Runnable.class ),
+                      ImmutableList.copyOf( bTv.getBounds() ) );
+        assertEquals( "B", bTv.toString() );
+        assertEqualsBothWays( bTl, TypeLiteral.get( HasTypeParameters.class.getTypeParameters()[1] ) );
+    }
+
+    class HasTypeParameters<A, B extends List<A> & Runnable, C extends Runnable>
+    {
+        A a;
+
+        B b;
+
+        C c;
+    }
+
+}

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/type/TypeLiteralTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain