| /* |
| * 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. |
| */ |
| package org.apache.webbeans.util; |
| |
| import java.lang.reflect.Array; |
| import java.lang.reflect.GenericArrayType; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.TypeVariable; |
| import java.lang.reflect.WildcardType; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import jakarta.enterprise.inject.spi.InjectionPoint; |
| |
| import org.apache.webbeans.exception.WebBeansConfigurationException; |
| import org.apache.webbeans.exception.WebBeansException; |
| |
| |
| /** |
| * Utility classes with respect to the class operations. |
| * |
| * @author <a href="mailto:gurkanerdogdu@yahoo.com">Gurkan Erdogdu</a> |
| * @since 1.0 |
| */ |
| public final class ClassUtil |
| { |
| public static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPERS_MAP; |
| public static final Map<Class<?>, Object> DEFAULT_VALUES_MAP; |
| |
| static |
| { |
| Map<Class<?>, Class<?>> primitiveToWrappersMap = new HashMap<>(); |
| primitiveToWrappersMap.put(Integer.TYPE,Integer.class); |
| primitiveToWrappersMap.put(Float.TYPE,Float.class); |
| primitiveToWrappersMap.put(Double.TYPE,Double.class); |
| primitiveToWrappersMap.put(Character.TYPE,Character.class); |
| primitiveToWrappersMap.put(Long.TYPE,Long.class); |
| primitiveToWrappersMap.put(Byte.TYPE,Byte.class); |
| primitiveToWrappersMap.put(Short.TYPE,Short.class); |
| primitiveToWrappersMap.put(Boolean.TYPE,Boolean.class); |
| primitiveToWrappersMap.put(Void.TYPE,Void.class); |
| PRIMITIVE_TO_WRAPPERS_MAP = Collections.unmodifiableMap(primitiveToWrappersMap); |
| Map<Class<?>, Object> defaultValuesMap = new HashMap<>(); |
| defaultValuesMap.put(Integer.TYPE, 0); |
| defaultValuesMap.put(Float.TYPE, 0F); |
| defaultValuesMap.put(Double.TYPE, 0D); |
| defaultValuesMap.put(Character.TYPE, '\u0000'); |
| defaultValuesMap.put(Long.TYPE, 0L); |
| defaultValuesMap.put(Byte.TYPE, (byte) 0); |
| defaultValuesMap.put(Short.TYPE, (short) 0); |
| defaultValuesMap.put(Boolean.TYPE, Boolean.FALSE); |
| DEFAULT_VALUES_MAP = Collections.unmodifiableMap(defaultValuesMap); |
| } |
| |
| public static final Type[] NO_TYPES = new Type[0]; |
| |
| /* |
| * Private constructor |
| */ |
| private ClassUtil() |
| { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public static Class<?> getClassFromName(String name) |
| { |
| return getClassFromName(name, WebBeansUtil.getCurrentClassLoader(), true); |
| } |
| |
| public static Class<?> getClassFromName(String name, ClassLoader providedLoader, boolean init) |
| { |
| Class<?> clazz; |
| ClassLoader loader = providedLoader; |
| try |
| { |
| clazz = Class.forName(name, init , loader); |
| return clazz; |
| |
| } |
| catch (ClassNotFoundException e) |
| { |
| try |
| { |
| loader = ClassUtil.class.getClassLoader(); |
| clazz = Class.forName(name, true , loader); |
| |
| return clazz; |
| |
| } |
| catch (ClassNotFoundException e1) |
| { |
| try |
| { |
| loader = ClassLoader.getSystemClassLoader(); |
| clazz = Class.forName(name, true , loader); |
| |
| return clazz; |
| |
| } |
| catch (ClassNotFoundException e2) |
| { |
| return null; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Check the class is inner or not |
| * |
| * @param clazz to check |
| * @return true or false |
| */ |
| public static boolean isInnerClazz(Class<?> clazz) |
| { |
| Asserts.nullCheckForClass(clazz); |
| |
| return clazz.isMemberClass(); |
| } |
| |
| public static boolean isSame(Type type1, Type type2) |
| { |
| if ((type1 instanceof Class) && ((Class<?>)type1).isPrimitive()) |
| { |
| type1 = PRIMITIVE_TO_WRAPPERS_MAP.get(type1); |
| } |
| if ((type2 instanceof Class) && ((Class<?>)type2).isPrimitive()) |
| { |
| type2 = PRIMITIVE_TO_WRAPPERS_MAP.get(type2); |
| } |
| return type1 == type2; |
| } |
| |
| public static Class<?> getPrimitiveWrapper(Class<?> clazz) |
| { |
| Asserts.nullCheckForClass(clazz); |
| |
| return PRIMITIVE_TO_WRAPPERS_MAP.get(clazz); |
| |
| } |
| |
| public static Object getDefaultValue(Class<?> type) |
| { |
| return DEFAULT_VALUES_MAP.get(type); |
| } |
| |
| /** |
| * Gets the class of the given type arguments. |
| * <p> |
| * If the given type {@link Type} parameters is an instance of the |
| * {@link ParameterizedType}, it returns the raw type otherwise it return |
| * the casted {@link Class} of the type argument. |
| * </p> |
| * |
| * @param type class or parametrized type |
| * @return |
| */ |
| public static Class<?> getClass(Type type) |
| { |
| return getClazz(type); |
| } |
| |
| |
| /** |
| * Check method throws checked exception or not. |
| * |
| * @param method method instance |
| */ |
| public static boolean isMethodHasCheckedException(Method method) |
| { |
| Asserts.nullCheckForMethod(method); |
| |
| Class<?>[] et = method.getExceptionTypes(); |
| |
| if (et.length > 0) |
| { |
| for (Class<?> type : et) |
| { |
| if (!Error.class.isAssignableFrom(type) && !RuntimeException.class.isAssignableFrom(type)) |
| { |
| return true; |
| } |
| } |
| |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Call method on the instance with given arguments. |
| * |
| * @param method method instance |
| * @param instance object instance |
| * @param args arguments |
| * @return the method result |
| */ |
| public static Object callInstanceMethod(Method method, Object instance, Object[] args) |
| { |
| Asserts.nullCheckForMethod(method); |
| |
| try |
| { |
| if (args == null) |
| { |
| args = new Object[] {}; |
| } |
| return method.invoke(instance, args); |
| |
| } |
| catch (Exception e) |
| { |
| throw new WebBeansException("Exception occurs in the method call with method : " + method.getName() + " in class : " + instance.getClass().getName(), e); |
| } |
| |
| } |
| |
| private static Set<String> getObjectMethodNames() |
| { |
| if (objectMethodNames == null) |
| { |
| // not much synchronisation needed... |
| Set<String> list = new HashSet<>(); |
| Class<?> clazz = Object.class; |
| |
| Method[] methods = clazz.getDeclaredMethods(); |
| for (Method method : methods) |
| { |
| list.add(method.getName()); |
| } |
| objectMethodNames = list; |
| } |
| |
| return objectMethodNames; |
| } |
| private static volatile Set<String> objectMethodNames; |
| |
| /** |
| * collect all non-private, non-static and non-abstract methods from the given class. |
| * This method removes any overloaded methods from the list automatically. |
| * We also skip JVM {@link Method#isBridge() bridge} methods by default; use |
| * {@link #getNonPrivateMethods(Class, boolean, boolean)} when a caller (e.g. normal-scope |
| * subclass proxies, OWB-1234/923) must list those signatures too. |
| * |
| * The returned Map contains the methods divided by the methodName as key in the map |
| * following all the methods with the same methodName in a List. |
| * |
| * There is some special rule for package-private methods. Any non-visible |
| * package-private method will get skipped and treated similarly to private methods. |
| * |
| * Note: we filter out the {@link Object#finalize()} method as users must not deal with it. |
| * @param topClass the class to start with. Then move up the hierarchy |
| * @param excludeFinalMethods whether final classes should get excluded from the result |
| */ |
| public static List<Method> getNonPrivateMethods(Class<?> topClass, boolean excludeFinalMethods) |
| { |
| return getNonPrivateMethods(topClass, excludeFinalMethods, false); |
| } |
| |
| /** |
| * @param includeJvmBridgeMethods when {@code true} (classes only), after the usual collection |
| * this method appends JVM bridge methods whose {@code name + JVM descriptor} is not |
| * already present (descriptor alone is insufficient: e.g. {@code clone()} and a covariant |
| * {@code getValue()} bridge can share {@code ()Ljava/lang/Object;}, OWB-923). |
| */ |
| public static List<Method> getNonPrivateMethods(Class<?> topClass, boolean excludeFinalMethods, |
| boolean includeJvmBridgeMethods) |
| { |
| Map<String, List<Method>> methodMap = new HashMap<>(); |
| List<Method> allMethods = new ArrayList<>(10); |
| // mirrors allMethods for O(1) membership checks (avoids O(n^2) List#contains with Method#equals) |
| Set<Method> allMethodsSet = new HashSet<>(); |
| |
| Class<?> clazz = topClass; |
| |
| if (!clazz.isAnnotation() && clazz.isInterface()) |
| { |
| addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, allMethodsSet, clazz, true); |
| for (Class<?> parent : clazz.getInterfaces()) |
| { |
| addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, allMethodsSet, parent, true); |
| } |
| } |
| else |
| { |
| // topClass.getMethods() already returns every public method in the whole hierarchy, so only the |
| // top class needs that (expensive) call; superclasses only add their declared (non-public) methods. |
| // Public methods declared higher up are already collected and deduped via allMethodsSet. |
| boolean topLevel = true; |
| while (clazz != null) |
| { |
| addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, allMethodsSet, clazz, topLevel); |
| topLevel = false; |
| clazz = clazz.getSuperclass(); |
| } |
| } |
| |
| if (includeJvmBridgeMethods && !topClass.isAnnotation() && !topClass.isInterface()) |
| { |
| appendJvmBridgeMethods(topClass, excludeFinalMethods, allMethods); |
| } |
| |
| return allMethods; |
| } |
| |
| /** |
| * Bridges are merged in a second pass with JVM-level descriptor keys so a covariant-return |
| * bridge (e.g. {@code ()Ljava/lang/Object;}) is not dropped as an "override" of |
| * {@code ()Ljava/lang/String;} during single-pass name-based collection. |
| */ |
| private static void appendJvmBridgeMethods(Class<?> topClass, boolean excludeFinalMethods, List<Method> allMethods) |
| { |
| // Name + JVM descriptor: covariant bridge getValue()Ljava/lang/Object; must not collide with |
| // Object.clone()Ljava/lang/Object; (same descriptor, different name — see OWB-923). |
| Set<String> signatureKeys = new HashSet<>(); |
| for (Method m : allMethods) |
| { |
| signatureKeys.add(jvmBridgeSignatureKey(m)); |
| } |
| for (Class<?> c = topClass; c != null && c != Object.class; c = c.getSuperclass()) |
| { |
| for (Method m : c.getDeclaredMethods()) |
| { |
| if (!m.isBridge()) |
| { |
| continue; |
| } |
| if (skipBridgeMethodForCollection(m, excludeFinalMethods, c, topClass)) |
| { |
| continue; |
| } |
| String key = jvmBridgeSignatureKey(m); |
| if (signatureKeys.contains(key)) |
| { |
| continue; |
| } |
| signatureKeys.add(key); |
| allMethods.add(m); |
| } |
| } |
| } |
| |
| private static String jvmBridgeSignatureKey(Method m) |
| { |
| return m.getName() + '\0' + org.apache.xbean.asm9.Type.getMethodDescriptor(m); |
| } |
| |
| private static boolean skipBridgeMethodForCollection(Method m, boolean excludeFinalMethods, |
| Class<?> declaringClass, Class<?> topClass) |
| { |
| int modifiers = m.getModifiers(); |
| if (Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) |
| { |
| return true; |
| } |
| if (excludeFinalMethods && Modifier.isFinal(modifiers)) |
| { |
| return true; |
| } |
| if ("finalize".equals(m.getName())) |
| { |
| return true; |
| } |
| if (!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) |
| { |
| if (!declaringClass.getPackage().getName().equals(topClass.getPackage().getName())) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static void addNonPrivateMethods(Class<?> topClass, boolean excludeFinalMethods, |
| Map<String, List<Method>> methodMap, List<Method> allMethods, |
| Set<Method> allMethodsSet, Class<?> clazz, boolean includeInheritedPublicMethods) |
| { |
| List<Method> temp; |
| if (includeInheritedPublicMethods) |
| { |
| Method[] classMethods = clazz.getMethods(); |
| Method[] declaredMethods = clazz.getDeclaredMethods(); |
| temp = new ArrayList<>(classMethods.length + declaredMethods.length); |
| Collections.addAll(temp, classMethods); |
| for (Method method : declaredMethods) |
| { |
| // a declared method is in getMethods() iff it is public, so only the non-public |
| // declared methods (private/protected/package) still need to be added here. |
| // This avoids both an O(n^2) List#contains and a temporary de-dup Set. |
| if (!Modifier.isPublic(method.getModifiers())) |
| { |
| temp.add(method); |
| } |
| } |
| } |
| else |
| { |
| // inherited public methods were already collected from the top class (and deduped via |
| // allMethodsSet below), so this level only needs to contribute its declared methods. |
| temp = Arrays.asList(clazz.getDeclaredMethods()); |
| } |
| |
| for (Method method : temp) |
| { |
| if (allMethodsSet.contains(method)) |
| { |
| continue; |
| } |
| |
| if (method.isBridge()) |
| { |
| // we have no interest in generics bridge methods for general API reflection |
| continue; |
| } |
| |
| int modifiers = method.getModifiers(); |
| |
| if (Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) |
| { |
| continue; |
| } |
| if (excludeFinalMethods && Modifier.isFinal(modifiers)) |
| { |
| continue; |
| } |
| |
| if ("finalize".equals(method.getName())) |
| { |
| // we do not proxy finalize() |
| continue; |
| } |
| |
| // check for package-private methods from a different package |
| if (!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) |
| { |
| // private already got handled above, so we only had to check for not public nor protected |
| // we cannot see those methods if they are not in the same package as the rootClazz |
| if (!clazz.getPackage().getName().equals(topClass.getPackage().getName())) |
| { |
| continue; |
| } |
| |
| } |
| |
| List<Method> methods = methodMap.get(method.getName()); |
| if (methods == null) |
| { |
| methods = new ArrayList<>(); |
| methods.add(method); |
| allMethods.add(method); |
| allMethodsSet.add(method); |
| methodMap.put(method.getName(), methods); |
| } |
| else |
| { |
| if (!isOverridden(methods, method)) |
| { |
| // method is not overridden, so add it |
| methods.add(method); |
| allMethods.add(method); |
| allMethodsSet.add(method); |
| } |
| } |
| } |
| } |
| |
| /** |
| * collect all abstract methods for the given class if the given class |
| * is {@link Modifier#ABSTRACT} |
| * |
| * @param clazz {@link Class} to check |
| * |
| * @return {@link List} with all abstract methods of the given class or an empty list |
| * if the given class is not abstract or doesn't contain an abstract method |
| */ |
| public static List<Method> getAbstractMethods(Class<?> clazz) |
| { |
| if (!Modifier.isAbstract(clazz.getModifiers())) |
| { |
| return Collections.emptyList(); |
| } |
| |
| List<Method> methods = getNonPrivateMethods(clazz, true); |
| if (!methods.isEmpty()) |
| { |
| methods.removeIf(method -> !Modifier.isAbstract(method.getModifiers())); |
| } |
| |
| return methods; |
| } |
| |
| /** |
| * Checks, if the given {@link Class} declares the {@link Method} with the |
| * given name und parameterTypes. |
| * |
| * @param clazz to check |
| * @param name of the method |
| * @param parameterTypes of the method |
| * |
| * @return {@code} true if the given class contains a method with the given name and parameterTypes, |
| * otherwise {@code false} |
| */ |
| public static boolean isMethodDeclared(Class<?> clazz, String name, Class<?>... parameterTypes) |
| { |
| try |
| { |
| clazz.getMethod(name, parameterTypes); |
| return true; |
| } |
| catch (NoSuchMethodException e) |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * Checks, if the given {@link Class} implements the {@link Method} with the |
| * given name und parameterTypes. |
| * Returns {@code false} if the method is only a default method in the interface! |
| * |
| * @param clazz to check |
| * @param interfase the Interface which declares the method |
| * @param methodName of the method |
| * @param parameterTypes of the method |
| * |
| * @return {@code} true if the given class contains a method with the given name and parameterTypes, |
| * otherwise {@code false} |
| */ |
| public static boolean isMethodImplemented(Class<?> clazz, Class<?> interfase, String methodName, Class<?>... parameterTypes) |
| { |
| try |
| { |
| Method m = clazz.getMethod(methodName, parameterTypes); |
| return m != null && m.getDeclaringClass() != interfase; |
| } |
| catch (NoSuchMethodException e) |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * Check if the method is already defined in a subclass |
| * @param subclassMethods |
| * @param superclassMethod |
| */ |
| public static boolean isOverridden(List<Method> subclassMethods, Method superclassMethod) |
| { |
| for (Method m : subclassMethods) |
| { |
| if (isOverridden(m, superclassMethod)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Checks if the given method if from Object.class |
| * @param methodName |
| * @return <code>true</code> if the given method is from Object.class (either directly or overloaded) |
| */ |
| public static boolean isObjectMethod(String methodName) |
| { |
| return getObjectMethodNames().contains(methodName); |
| } |
| |
| /** |
| * Returns true if type is an instance of <code>ParameterizedType</code> |
| * else otherwise. |
| * |
| * @param type type of the artifact |
| * @return true if type is an instance of <code>ParameterizedType</code> |
| */ |
| public static boolean isParametrizedType(Type type) |
| { |
| return type instanceof ParameterizedType; |
| } |
| |
| /** |
| * Returns true if type is an instance of <code>WildcardType</code> |
| * else otherwise. |
| * |
| * @param type type of the artifact |
| * @return true if type is an instance of <code>WildcardType</code> |
| */ |
| public static boolean isWildCardType(Type type) |
| { |
| Asserts.assertNotNull(type, "type"); |
| |
| return type instanceof WildcardType; |
| } |
| |
| public static boolean isUnboundedTypeVariable(Type type) |
| { |
| Asserts.assertNotNull(type, "type"); |
| |
| if (type instanceof TypeVariable) |
| { |
| TypeVariable wc = (TypeVariable)type; |
| Type[] upper = wc.getBounds(); |
| |
| |
| if(upper.length > 1) |
| { |
| return false; |
| } |
| else |
| { |
| Type arg = upper[0]; |
| if(!(arg instanceof Class)) |
| { |
| return false; |
| } |
| else |
| { |
| Class<?> clazz = (Class<?>)arg; |
| if(!clazz.equals(Object.class)) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| else |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| /** |
| * Returns true if type is an instance of <code>TypeVariable</code> |
| * else otherwise. |
| * |
| * @param type type of the artifact |
| * @return true if type is an instance of <code>TypeVariable</code> |
| */ |
| public static boolean isTypeVariable(Type type) |
| { |
| Asserts.assertNotNull(type, "type"); |
| |
| return type instanceof TypeVariable; |
| } |
| |
| |
| /** |
| * Return true if the class is not abstract and interface. |
| * |
| * @param clazz class type |
| * @return true if the class is not abstract and interface |
| */ |
| public static boolean isConcrete(Class<?> clazz) |
| { |
| Asserts.nullCheckForClass(clazz); |
| |
| int modifier = clazz.getModifiers(); |
| |
| return !Modifier.isAbstract(modifier) && !Modifier.isInterface(modifier); |
| } |
| |
| |
| /** |
| * Returns true if rhs is assignable type |
| * to the lhs, false otherwise. |
| * |
| * @param lhs left hand side class |
| * @param rhs right hand side class |
| * @return true if rhs is assignable to lhs |
| */ |
| public static boolean isClassAssignableFrom(Class<?> lhs, Class<?> rhs) |
| { |
| Asserts.assertNotNull(lhs, "lhs"); |
| Asserts.assertNotNull(rhs, "rhs"); |
| |
| if(lhs.isPrimitive()) |
| { |
| lhs = getPrimitiveWrapper(lhs); |
| } |
| |
| if(rhs.isPrimitive()) |
| { |
| rhs = getPrimitiveWrapper(rhs); |
| } |
| |
| if (lhs.isAssignableFrom(rhs)) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Check bean type and required type. |
| * <p> |
| * Required type is a wildcard type. |
| * </p> |
| * @param beanTypeArg bean type |
| * @param requiredTypeArg required type |
| * @return true if condition satisfies |
| * @since 1.1.1 |
| */ |
| public static boolean checkRequiredTypeIsWildCard(Type beanTypeArg, Type requiredTypeArg) |
| { |
| WildcardType wctRequiredTypeArg = (WildcardType)requiredTypeArg; |
| Type upperBoundRequiredTypeArg = wctRequiredTypeArg.getUpperBounds()[0]; |
| Type[] lowerBoundRequiredTypeArgs = wctRequiredTypeArg.getLowerBounds(); |
| |
| if(beanTypeArg instanceof Class) |
| { |
| Class<?> clazzBeanTypeArg = (Class<?>)beanTypeArg; |
| if(upperBoundRequiredTypeArg instanceof Class) |
| { |
| //Check upper bounds |
| Class<?> clazzUpperBoundTypeArg = (Class<?>)upperBoundRequiredTypeArg; |
| if(clazzUpperBoundTypeArg != Object.class) |
| { |
| if(!clazzUpperBoundTypeArg.isAssignableFrom(clazzBeanTypeArg)) |
| { |
| return false; |
| } |
| } |
| |
| //Check lower bounds |
| if(lowerBoundRequiredTypeArgs.length > 0 && lowerBoundRequiredTypeArgs[0] instanceof Class) |
| { |
| Class<?> clazzLowerBoundTypeArg = (Class<?>)lowerBoundRequiredTypeArgs[0]; |
| |
| if(clazzLowerBoundTypeArg != Object.class) |
| { |
| if(!clazzBeanTypeArg.isAssignableFrom(clazzLowerBoundTypeArg)) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| } |
| else if(isTypeVariable(beanTypeArg)) |
| { |
| TypeVariable<?> tvBeanTypeArg = (TypeVariable<?>)beanTypeArg; |
| Type tvBound = tvBeanTypeArg.getBounds()[0]; |
| |
| if(tvBound instanceof Class) |
| { |
| Class<?> clazzTvBound = (Class<?>)tvBound; |
| |
| if(upperBoundRequiredTypeArg instanceof Class) |
| { |
| Class<?> clazzUpperBoundTypeArg = (Class<?>)upperBoundRequiredTypeArg; |
| if(clazzUpperBoundTypeArg != Object.class && clazzTvBound != Object.class) |
| { |
| if(!clazzUpperBoundTypeArg.isAssignableFrom(clazzTvBound)) |
| { |
| return false; |
| } |
| } |
| |
| //Check lower bounds |
| if(lowerBoundRequiredTypeArgs.length > 0 && lowerBoundRequiredTypeArgs[0] instanceof Class) |
| { |
| Class<?> clazzLowerBoundTypeArg = (Class<?>)lowerBoundRequiredTypeArgs[0]; |
| |
| if(clazzLowerBoundTypeArg != Object.class) |
| { |
| if(!clazzTvBound.isAssignableFrom(clazzLowerBoundTypeArg)) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| } |
| } |
| else if (beanTypeArg instanceof ParameterizedType) |
| { |
| final ParameterizedType pt = (ParameterizedType) beanTypeArg; |
| if(pt.getRawType() instanceof Class && upperBoundRequiredTypeArg instanceof Class) |
| { |
| final Class<?> beanRawClass = (Class) pt.getRawType(); |
| |
| //Check upper bounds |
| Class<?> clazzUpperBoundTypeArg = (Class<?>)upperBoundRequiredTypeArg; |
| if(clazzUpperBoundTypeArg != Object.class) |
| { |
| if(!clazzUpperBoundTypeArg.isAssignableFrom(beanRawClass)) |
| { |
| return false; |
| } |
| } |
| |
| //Check lower bounds |
| if(lowerBoundRequiredTypeArgs.length > 0 && lowerBoundRequiredTypeArgs[0] instanceof Class) |
| { |
| Class<?> clazzLowerBoundTypeArg = (Class<?>)lowerBoundRequiredTypeArgs[0]; |
| |
| if(clazzLowerBoundTypeArg != Object.class && !beanRawClass.isAssignableFrom(clazzLowerBoundTypeArg)) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Returns declared type arguments if {@code type} is a |
| * {@link ParameterizedType} instance, else an empty array. |
| * Get the actual type arguments of a type. |
| * @param type |
| * @return array of type arguments available |
| * @since 1.1.1 |
| */ |
| public static Type[] getActualTypeArguments(Type type) |
| { |
| Asserts.assertNotNull(type, "type"); |
| |
| if (type instanceof ParameterizedType) |
| { |
| return ((ParameterizedType) type).getActualTypeArguments(); |
| |
| } |
| else |
| { |
| return NO_TYPES; |
| } |
| } |
| |
| /** |
| * Return raw class type for given type. |
| * @param type base type instance |
| * @return class type for given type |
| */ |
| public static Class<?> getClazz(Type type) |
| { |
| if(type instanceof Class) |
| { |
| return (Class<?>)type; |
| } |
| else if(type instanceof ParameterizedType) |
| { |
| ParameterizedType pt = (ParameterizedType)type; |
| return (Class<?>)pt.getRawType(); |
| } |
| else if(type instanceof GenericArrayType) |
| { |
| GenericArrayType arrayType = (GenericArrayType)type; |
| return Array.newInstance(getClazz(arrayType.getGenericComponentType()), 0).getClass(); |
| } |
| else if (type instanceof WildcardType) |
| { |
| WildcardType wildcardType = (WildcardType)type; |
| Type[] bounds = wildcardType.getUpperBounds(); |
| if (bounds.length > 1) |
| { |
| throw new WebBeansConfigurationException("Illegal use of wild card type with more than one upper bound: " + wildcardType); |
| } |
| else if (bounds.length == 0) |
| { |
| return Object.class; |
| } |
| else |
| { |
| return getClass(bounds[0]); |
| } |
| } |
| else if (type instanceof TypeVariable) |
| { |
| TypeVariable<?> typeVariable = (TypeVariable<?>)type; |
| if (typeVariable.getBounds().length > 1) |
| { |
| throw new WebBeansConfigurationException("Illegal use of type variable with more than one bound: " + typeVariable); |
| } |
| else |
| { |
| Type[] bounds = typeVariable.getBounds(); |
| if (bounds.length == 0) |
| { |
| return Object.class; |
| } |
| else |
| { |
| return getClass(bounds[0]); |
| } |
| } |
| } |
| else |
| { |
| throw new WebBeansConfigurationException("Unsupported type " + type); |
| } |
| } |
| |
| /** |
| * Return true if it does not contain type variable for wildcard type |
| * false otherwise. |
| * |
| * @param pType parameterized type |
| * @return true if it does not contain type variable for wildcard type |
| */ |
| public static boolean checkParametrizedType(ParameterizedType pType) |
| { |
| Asserts.assertNotNull(pType, "pType"); |
| |
| Type[] types = pType.getActualTypeArguments(); |
| |
| for (Type type : types) |
| { |
| if (type instanceof ParameterizedType) |
| { |
| return checkParametrizedType((ParameterizedType) type); |
| } |
| else if ((type instanceof TypeVariable) || (type instanceof WildcardType)) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| /** |
| * Returns injection point raw type. |
| * |
| * @param injectionPoint injection point definition |
| * @return injection point raw type |
| */ |
| public static Class<?> getRawTypeForInjectionPoint(InjectionPoint injectionPoint) |
| { |
| Class<?> rawType = null; |
| Type type = injectionPoint.getType(); |
| |
| if(type instanceof Class) |
| { |
| rawType = (Class<?>) type; |
| } |
| else if(type instanceof ParameterizedType) |
| { |
| ParameterizedType pt = (ParameterizedType)type; |
| rawType = (Class<?>)pt.getRawType(); |
| } |
| |
| return rawType; |
| } |
| |
| /** |
| * Check whether <code>superClassMethod</code> is overridden by <code>subClassMethod</code>. |
| * @param subClassMethod potentially overriding |
| * @param superClassMethod potentially overridden |
| * @return true if overridden |
| * @since 1.1.1 |
| */ |
| public static boolean isOverridden(Method subClassMethod, Method superClassMethod) |
| { |
| if (isSuperClass(superClassMethod.getDeclaringClass(), subClassMethod.getDeclaringClass()) |
| && subClassMethod.getName().equals(superClassMethod.getName()) |
| && Arrays.equals(subClassMethod.getParameterTypes(), superClassMethod.getParameterTypes())) |
| { |
| int modifiers = superClassMethod.getModifiers(); |
| if(Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) |
| { |
| return false; |
| } |
| |
| if(!Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers)) |
| { |
| Class<?> superClass = superClassMethod.getDeclaringClass(); |
| Class<?> subClass = subClassMethod.getDeclaringClass(); |
| |
| //Same package |
| if(!subClass.getPackage().getName().equals(superClass.getPackage().getName())) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| private static boolean isSuperClass(Class<?> superClass, Class<?> subClass) |
| { |
| return superClass.isAssignableFrom(subClass) && !superClass.equals(subClass); |
| } |
| |
| public static boolean isRawClassEquals(Type ipType, Type apiType) |
| { |
| Class ipClass = getRawPrimitiveType(ipType); |
| Class apiClass = getRawPrimitiveType(apiType); |
| |
| if (ipClass == null || apiClass == null) |
| { |
| // we found some illegal types |
| return false; |
| } |
| |
| return ipClass.equals(apiClass); |
| } |
| |
| public static Class getRawPrimitiveType(Type type) |
| { |
| if (type instanceof Class) |
| { |
| if (((Class) type).isPrimitive()) |
| { |
| return getPrimitiveWrapper((Class) type); |
| } |
| return (Class) type; |
| } |
| |
| if (type instanceof ParameterizedType) |
| { |
| return getRawPrimitiveType(((ParameterizedType) type).getRawType()); |
| } |
| |
| return null; |
| } |
| } |