Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source
   * Copyright 2014, Red Hat, Inc., and individual contributors
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
  * http://www.apache.org/licenses/LICENSE-2.0
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package org.jboss.weld.resolution;
 
 import static org.jboss.weld.util.Types.boxedClass;
 
 
Utility class that captures standard covariant Java assignability rules. This class operates on all the possible Type subtypes: Class, ParameterizedType, TypeVariable, WildcardType, GenericArrayType. To make this class easier to understand and maintain, there is a separate isAssignableFrom method for each combination of possible types. Each of these methods compares two type instances and determines whether the first one is assignable from the other. TypeVariables are considered a specific unknown type restricted by the upper bound. No inference of type variables is performed.

Author(s):
Jozef Hartinger
 
 public class CovariantTypes {
 
     private CovariantTypes() {
     }
 
     public static boolean isAssignableFromAtLeastOne(Type type1Type[] types2) {
         for (Type type2 : types2) {
             if (isAssignableFrom(type1type2)) {
                 return true;
             }
         }
         return false;
     }
 
     public static boolean isAssignableFrom(Type type1Type type2) {
         if (type1 instanceof Class<?>) {
             if (type2 instanceof Class<?>) {
                 return isAssignableFrom((Class<?>) type1, (Class<?>) type2);
             }
             if (type2 instanceof ParameterizedType) {
                 return isAssignableFrom((Class<?>) type1, (ParameterizedTypetype2);
             }
             if (type2 instanceof TypeVariable<?>) {
                 return isAssignableFrom((Class<?>) type1, (TypeVariable<?>) type2);
             }
             if (type2 instanceof WildcardType) {
                 return isAssignableFrom((Class<?>) type1, (WildcardTypetype2);
             }
             if (type2 instanceof GenericArrayType) {
                 return isAssignableFrom((Class<?>) type1, (GenericArrayTypetype2);
             }
             throw ..unknownType(type2);
         }
         if (type1 instanceof ParameterizedType) {
             if (type2 instanceof Class<?>) {
                 return isAssignableFrom((ParameterizedTypetype1, (Class<?>) type2);
             }
             if (type2 instanceof ParameterizedType) {
                 return isAssignableFrom((ParameterizedTypetype1, (ParameterizedTypetype2);
             }
             if (type2 instanceof TypeVariable<?>) {
                 return isAssignableFrom((ParameterizedTypetype1, (TypeVariable<?>) type2);
             }
             if (type2 instanceof WildcardType) {
                 return isAssignableFrom((ParameterizedTypetype1, (WildcardTypetype2);
             }
             if (type2 instanceof GenericArrayType) {
                 return isAssignableFrom((ParameterizedTypetype1, (GenericArrayTypetype2);
             }
             throw ..unknownType(type2);
         }
         if (type1 instanceof TypeVariable<?>) {
             if (type2 instanceof Class<?>) {
                 return isAssignableFrom((TypeVariable<?>) type1, (Class<?>) type2);
             }
            if (type2 instanceof ParameterizedType) {
                return isAssignableFrom((TypeVariable<?>) type1, (ParameterizedTypetype2);
            }
            if (type2 instanceof TypeVariable<?>) {
                return isAssignableFrom((TypeVariable<?>) type1, (TypeVariable<?>) type2);
            }
            if (type2 instanceof WildcardType) {
                return isAssignableFrom((TypeVariable<?>) type1, (WildcardTypetype2);
            }
            if (type2 instanceof GenericArrayType) {
                return isAssignableFrom((TypeVariable<?>) type1, (GenericArrayTypetype2);
            }
            throw ..unknownType(type2);
        }
        if (type1 instanceof WildcardType) {
            if (Types.isActualType(type2)) {
                return isAssignableFrom((WildcardTypetype1type2);
            }
            if (type2 instanceof TypeVariable<?>) {
                return isAssignableFrom((WildcardTypetype1, (TypeVariable<?>) type2);
            }
            if (type2 instanceof WildcardType) {
                return isAssignableFrom((WildcardTypetype1, (WildcardTypetype2);
            }
            throw ..unknownType(type2);
        }
        if (type1 instanceof GenericArrayType) {
            if (type2 instanceof Class<?>) {
                return isAssignableFrom((GenericArrayTypetype1, (Class<?>) type2);
            }
            if (type2 instanceof ParameterizedType) {
                return isAssignableFrom((GenericArrayTypetype1, (ParameterizedTypetype2);
            }
            if (type2 instanceof TypeVariable<?>) {
                return isAssignableFrom((GenericArrayTypetype1, (TypeVariable<?>) type2);
            }
            if (type2 instanceof WildcardType) {
                return isAssignableFrom((GenericArrayTypetype1, (WildcardTypetype2);
            }
            if (type2 instanceof GenericArrayType) {
                return isAssignableFrom((GenericArrayTypetype1, (GenericArrayTypetype2);
            }
            throw ..unknownType(type2);
        }
        throw ..unknownType(type1);
    }
    /*
     * Raw type
     */
    private static boolean isAssignableFrom(Class<?> type1Class<?> type2) {
        return boxedClass(type1).isAssignableFrom(boxedClass(type2));
    }
    private static boolean isAssignableFrom(Class<?> type1ParameterizedType type2) {
        return type1.isAssignableFrom(Reflections.getRawType(type2));
    }
    private static boolean isAssignableFrom(Class<?> type1TypeVariable<?> type2) {
        for (Type type : type2.getBounds()) {
            if (isAssignableFrom(type1type)) {
                return true;
            }
        }
        return false;
    }
    private static boolean isAssignableFrom(Class<?> type1WildcardType type2) {
        return false;
    }
    private static boolean isAssignableFrom(Class<?> type1GenericArrayType type2) {
        return type1.equals(Object.class) || type1.isArray()
                && isAssignableFrom(type1.getComponentType(), Reflections.getRawType(type2.getGenericComponentType()));
    }
    /*
     * ParameterizedType
     */
    private static boolean isAssignableFrom(ParameterizedType type1Class<?> type2) {
        Class<?> rawType1 = Reflections.getRawType(type1);
        // raw types have to be assignable
        if (!isAssignableFrom(rawType1type2)) {
            return false;
        }
        // this is a raw type with missing type arguments
        if (!Types.getCanonicalType(type2).equals(type2)) {
            return true;
        }
        return matches(type1new HierarchyDiscovery(type2));
    }
    private static boolean isAssignableFrom(ParameterizedType type1ParameterizedType type2) {
        // first, raw types have to be assignable
        if (!isAssignableFrom(Reflections.getRawType(type1), Reflections.getRawType(type2))) {
            return false;
        }
        if (matches(type1type2)) {
            return true;
        }
        return matches(type1new HierarchyDiscovery(type2));
    }
    private static boolean matches(ParameterizedType type1HierarchyDiscovery type2) {
        for (Type type : type2.getTypeClosure()) {
            if (type instanceof ParameterizedType && matches(type1, (ParameterizedTypetype)) {
                return true;
            }
        }
        return false;
    }
    private static boolean matches(ParameterizedType type1ParameterizedType type2) {
        final Class<?> rawType1 = Reflections.getRawType(type1);
        final Class<?> rawType2 = Reflections.getRawType(type2);
        if (!rawType1.equals(rawType2)) {
            return false;
        }
        final Type[] types1 = type1.getActualTypeArguments();
        final Type[] types2 = type2.getActualTypeArguments();
        if (types1.length != types2.length) {
            throw ..invalidTypeArgumentCombination(type1type2);
        }
        for (int i = 0; i < type1.getActualTypeArguments().lengthi++) {
            // Generics are invariant
            if (!InvariantTypes.isAssignableFrom(types1[i], types2[i])) {
                return false;
            }
        }
        return true;
    }
    private static boolean isAssignableFrom(ParameterizedType type1TypeVariable<?> type2) {
        for (Type type : type2.getBounds()) {
            if (isAssignableFrom(type1type)) {
                return true;
            }
        }
        return false;
    }
    private static boolean isAssignableFrom(ParameterizedType type1WildcardType type2) {
        return false;
    }
    private static boolean isAssignableFrom(ParameterizedType type1GenericArrayType type2) {
        return false;
    }
    /*
     * Type variable
     */
    private static boolean isAssignableFrom(TypeVariable<?> type1Class<?> type2) {
        return false;
    }
    private static boolean isAssignableFrom(TypeVariable<?> type1ParameterizedType type2) {
        return false;
    }

    
Returns true if type2 is a "sub-variable" of type1, i.e. if they are equal or if type2 (transitively) extends type1.
    private static boolean isAssignableFrom(TypeVariable<?> type1TypeVariable<?> type2) {
        if (type1.equals(type2)) {
            return true;
        }
        // if a type variable extends another type variable, it cannot declare other bounds
        if (type2.getBounds()[0] instanceof TypeVariable<?>) {
            return isAssignableFrom(type1, (TypeVariable<?>) type2.getBounds()[0]);
        }
        return false;
    }
    private static boolean isAssignableFrom(TypeVariable<?> type1WildcardType type2) {
        return false;
    }
    private static boolean isAssignableFrom(TypeVariable<?> type1GenericArrayType type2) {
        return false;
    }
    /*
     * Wildcard
     */

    
This logic is shared for all actual types i.e. raw types, parameterized types and generic array types.
    private static boolean isAssignableFrom(WildcardType type1Type type2) {
        if (!isAssignableFrom(type1.getUpperBounds()[0], type2)) {
            return false;
        }
        if (type1.getLowerBounds().length > 0 && !isAssignableFrom(type2type1.getLowerBounds()[0])) {
            return false;
        }
        return true;
    }
    private static boolean isAssignableFrom(WildcardType type1TypeVariable<?> type2) {
        if (type1.getLowerBounds().length > 0) {
            return isAssignableFrom(type2type1.getLowerBounds()[0]);
        }
        return isAssignableFrom(type1.getUpperBounds()[0], type2);
    }
    private static boolean isAssignableFrom(WildcardType type1WildcardType type2) {
        if (!isAssignableFrom(type1.getUpperBounds()[0], type2.getUpperBounds()[0])) {
            return false;
        }
        if (type1.getLowerBounds().length > 0) {
            // the first type defines a lower bound
            if (type2.getLowerBounds().length > 0) {
                return isAssignableFrom(type2.getLowerBounds()[0], type1.getLowerBounds()[0]);
            } else {
                return false;
            }
        } else if (type2.getLowerBounds().length > 0) {
            // only the second type defines a lower bound
            return type1.getUpperBounds()[0].equals(Object.class);
        }
        return true;
    }
    /*
     * GenericArrayType
     */
    private static boolean isAssignableFrom(GenericArrayType type1Class<?> type2) {
        return type2.isArray() && isAssignableFrom(Reflections.getRawType(type1.getGenericComponentType()), type2.getComponentType());
    }
    private static boolean isAssignableFrom(GenericArrayType type1ParameterizedType type2) {
        return false;
    }
    private static boolean isAssignableFrom(GenericArrayType type1TypeVariable<?> type2) {
        /*
         * JLS does not allow array types to be used as bounds of type variables
         */
        return false;
    }
    private static boolean isAssignableFrom(GenericArrayType type1WildcardType type2) {
        return false;
    }
    private static boolean isAssignableFrom(GenericArrayType type1GenericArrayType type2) {
        return isAssignableFrom(type1.getGenericComponentType(), type2.getGenericComponentType());
    }
New to GrepCode? Check out our FAQ X