/* * 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 java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.jboss.weld.util.reflection.Reflections; /** * * A util for deciding whether two {@link Type}s are the same (not necessarily equal in the java sense). * * @author Matus Abaffy */ public class TypeEqualitySpecializationUtils { private TypeEqualitySpecializationUtils() { } public static boolean areTheSame(Type type1, Type type2) { if (type1.equals(type2)) { return true; } if (type1 instanceof ParameterizedType && type2 instanceof ParameterizedType) { return areTheSame((ParameterizedType) type1, (ParameterizedType) type2); } if (type1 instanceof TypeVariable<?> && type2 instanceof TypeVariable<?>) { return areTheSame((TypeVariable<?>) type1, (TypeVariable<?>) type2); } return false; } protected static boolean areTheSame(ParameterizedType type1, ParameterizedType type2) { if (!type1.getRawType().equals(type2.getRawType())) { return false; } return areTheSame(type1.getActualTypeArguments(), type2.getActualTypeArguments()); } protected static boolean areTheSame(TypeVariable<?> type1, TypeVariable<?> type2) { List<Type> bounds1 = removeRedundantBounds(type1.getBounds()); List<Type> bounds2 = removeRedundantBounds(type2.getBounds()); if (bounds1.size() != bounds2.size()) { return false; } // each bound from bounds_i have to be in bounds_j, i.e. members of bounds1 have to be the same as members of bounds2 for (Type type : bounds1) { if (!isTheSameAsSomeOf(type, bounds2)) { return false; } } return true; } private static boolean isTheSameAsSomeOf(Type bound1, List<Type> bounds2) { for (Type type : bounds2) { if (areTheSame(bound1, type)) { return true; } } return false; } /** * Removes all instances of {@link Class} and {@link ParameterizedType} for which a subtype is present in 'bounds' */ private static List<Type> removeRedundantBounds(final Type[] bounds) { if (bounds.length == 1) { return Collections.singletonList(bounds[0]); } // if TypeVariable S has a bound T that is a TypeVariable, than S cannot have any other bounds, i.e. bounds.lenght == 1 List<Type> result = new LinkedList<Type>(); for (int i = 0; i < bounds.length; i++) { boolean isRedundant = false; for (int j = 0; j < bounds.length && i != j; j++) { if (Reflections.getRawType(bounds[i]).isAssignableFrom(Reflections.getRawType(bounds[j]))) { isRedundant = true; break; } } if (!isRedundant) { result.add(bounds[i]); } } return result; } protected static boolean areTheSame(Type[] types1, Type[] types2) { if (types1.length != types2.length) { return false; } for (int i = 0; i < types1.length; i++) { if (!areTheSame(types1[i], types2[i])) { return false; } } return true; } }