001    // Copyright 2006 Waterken Inc. under the terms of the MIT X license
002    // found at http://www.opensource.org/licenses/mit-license.html
003    package org.ref_send.type;
004    
005    import java.lang.reflect.ParameterizedType;
006    import java.lang.reflect.Type;
007    import java.lang.reflect.TypeVariable;
008    import java.lang.reflect.WildcardType;
009    
010    /**
011     * Type definition manipulation.
012     */
013    public final class
014    Typedef {
015        private Typedef() {}
016    
017        /**
018         * Gets the named type variable.
019         * @param declaration   generic declaration
020         * @param name          variable name
021         * @return corresponding type variable
022         * @throws NullPointerException no matching variable found
023         */
024        static public <T> TypeVariable<Class<T>>
025        var(final Class<T> declaration, final String name) {
026            for (final TypeVariable<Class<T>> i : declaration.getTypeParameters()) {
027                if (i.getName().equals(name)) { return i; }
028            }
029            throw new NullPointerException();
030        }
031    
032        /**
033         * Gets the value of a type variable.
034         * @param p type variable
035         * @param a instantiated type
036         * @return type argument, or <code>null</code> if <code>p</code> is not from
037         *         <code>a</code> or one of its super types
038         */
039        static public Type
040        value(final TypeVariable<?> p, final Type a) {
041            Type r;
042            final Class<?> template = raw(a);
043            final Class<?> declaration = (Class<?>)p.getGenericDeclaration();
044            if (declaration == template) {
045                r = p;
046            } else if (declaration.isAssignableFrom(template)) {
047                r = null;
048                for (final Type i : template.getGenericInterfaces()) {
049                    r = value(p, i);
050                    if (null != r) { break; }
051                }
052                if (null == r) {
053                    r = value(p, template.getGenericSuperclass());
054                }
055            } else {
056                return null;
057            }
058            if (r instanceof TypeVariable<?>) {
059                if (a instanceof ParameterizedType) {
060                    int i = 0;
061                    for (final TypeVariable<?> v : declaration.getTypeParameters()){
062                        if (p.equals(v)) { break; }
063                        ++i;
064                    }
065                    r = ((ParameterizedType)a).getActualTypeArguments()[i];
066                } else {
067                    r = Object.class;   // Class implements the raw type.
068                }
069            }
070            return r;
071        }
072    
073        /**
074         * Determine the corresponding raw type.
075         * @param type  generic type
076         * @return corresponding raw type
077         */
078        static public Class<?>
079        raw(final Type type) {
080            return type instanceof Class<?>
081                ? (Class<?>)type
082            : (type instanceof ParameterizedType
083                ? raw(((ParameterizedType)type).getRawType())
084            : (type instanceof WildcardType
085                ? raw(((WildcardType)type).getUpperBounds()[0])
086            : Object.class));
087        }
088        
089        /**
090         * Determine the upper bound on a type parameter.
091         * @param parameter generic parameter type
092         * @param declared  generic class type
093         * @return upper bound on the actual type
094         */
095        static public Type
096        bound(final Type parameter, final Type declared) {
097            final Type argument = parameter instanceof TypeVariable<?>
098                ? value((TypeVariable<?>)parameter, declared)
099            : parameter;
100            return argument instanceof WildcardType
101                ? ((WildcardType)argument).getUpperBounds()[0]
102            : argument;
103        }
104     }