/* * 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.lang.reflect.WildcardType; import org.jboss.weld.logging.ReflectionLogger; import org.jboss.weld.util.Types; import org.jboss.weld.util.reflection.HierarchyDiscovery; import org.jboss.weld.util.reflection.Reflections; /** * This class implements Section 10.3.1 of the CDI specification. * * @author Jozef Hartinger * */ public class EventTypeAssignabilityRules extends AbstractAssignabilityRules { private static final AssignabilityRules INSTANCE = new EventTypeAssignabilityRules(); public static AssignabilityRules instance() { return INSTANCE; } private EventTypeAssignabilityRules() { } @Override public boolean matches(Type observedType, Type eventType) { return matchesNoBoxing(Types.boxedType(observedType), Types.boxedType(eventType)); } public boolean matchesNoBoxing(Type observedType, Type eventType) { /* * Special handling for array event types as eventType closure does not contain the type closure of array component type * this is here for backwards compatibility - see ObserverMethodWithParametertizedTypeTest.testObserverMethodCanObserveArrayWildcard() */ if (Types.isArray(observedType) && Types.isArray(eventType)) { final Type observedComponentType = Types.getArrayComponentType(observedType); for (Type type : new HierarchyDiscovery(Types.getArrayComponentType(eventType)).getTypeClosure()) { if (matchesNoBoxing(observedComponentType, type)) { return true; } } return false; } if (observedType instanceof TypeVariable<?>) { /* * An event type is considered assignable to a type variable if the event type is assignable to the * upper bound, if any. */ return matches((TypeVariable<?>) observedType, eventType); } if (observedType instanceof Class<?> && eventType instanceof ParameterizedType) { /* * A parameterized event type is considered assignable to a raw observed event type if the raw * types are identical. */ return observedType.equals(Reflections.getRawType(eventType)); } if (observedType instanceof ParameterizedType && eventType instanceof ParameterizedType) { /* * A parameterized event type is considered assignable to a parameterized observed event type if * they have identical raw type and for each parameter: */ return matches((ParameterizedType) observedType, (ParameterizedType) eventType); } /* * Not explicitly said in the spec but obvious. */ if (observedType instanceof Class<?> && eventType instanceof Class<?>) { return observedType.equals(eventType); } return false; } private boolean matches(TypeVariable<?> observedType, Type eventType) { for (Type bound : getUppermostTypeVariableBounds(observedType)) { if (!CovariantTypes.isAssignableFrom(bound, eventType)) { return false; } } return true; } private boolean matches(ParameterizedType observedType, ParameterizedType eventType) { if (!observedType.getRawType().equals(eventType.getRawType())) { return false; } if (observedType.getActualTypeArguments().length != eventType.getActualTypeArguments().length) { throw ReflectionLogger.LOG.invalidTypeArgumentCombination(observedType, eventType); } for (int i = 0; i < observedType.getActualTypeArguments().length; i++) { if (!parametersMatch(observedType.getActualTypeArguments()[i], eventType.getActualTypeArguments()[i])) { return false; } } return true; } /** * A parameterized event type is considered assignable to a parameterized observed event type if * they have identical raw type and for each parameter: */ private boolean parametersMatch(Type observedParameter, Type eventParameter) { if (Types.isActualType(observedParameter) && Types.isActualType(eventParameter)) { /* * the observed event type parameter is an actual type with identical raw type to the event type * parameter, and, if the type is parameterized, the event type parameter is assignable to the * observed event type parameter according to these rules, or */ return matches(observedParameter, eventParameter); } if (observedParameter instanceof WildcardType && eventParameter instanceof WildcardType) { /* * both the observed event type parameter and the event type parameter are wildcards, and the event type parameter is assignable to the observed event * type */ return CovariantTypes.isAssignableFrom(observedParameter, eventParameter); } if (observedParameter instanceof WildcardType) { /* * the observed event type parameter is a wildcard and the event type parameter is assignable * to the upper bound, if any, of the wildcard and assignable from the lower bound, if any, of the * wildcard, or */ return parametersMatch((WildcardType) observedParameter, eventParameter); } if (observedParameter instanceof TypeVariable<?>) { /* * the observed event type parameter is a type variable and the event type parameter is assignable * to the upper bound, if any, of the type variable. */ return parametersMatch((TypeVariable<?>) observedParameter, eventParameter); } return false; } private boolean parametersMatch(TypeVariable<?> observedParameter, Type eventParameter) { for (Type bound : getUppermostTypeVariableBounds(observedParameter)) { if (!CovariantTypes.isAssignableFrom(bound, eventParameter)) { return false; } } return true; } private boolean parametersMatch(WildcardType observedParameter, Type eventParameter) { return (lowerBoundsOfWildcardMatch(eventParameter, observedParameter) && upperBoundsOfWildcardMatch(observedParameter, eventParameter)); } }