org.apache.webbeans.util.ClassUtil Maven / Gradle / Ivy
/*
* 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.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.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 Gurkan Erdogdu
* @since 1.0
*/
public final class ClassUtil
{
public static final Map, Class>> PRIMITIVE_TO_WRAPPERS_MAP;
public static final Map, Object> DEFAULT_VALUES_MAP;
static
{
Map, 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, 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)
{
Class> clazz;
ClassLoader loader;
try
{
loader = WebBeansUtil.getCurrentClassLoader();
clazz = Class.forName(name, true , 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.
*
* 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.
*
*
* @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 getObjectMethodNames()
{
if (objectMethodNames == null)
{
// not much synchronisation needed...
Set list = new HashSet<>();
Class> clazz = Object.class;
Method[] methods = SecurityUtil.doPrivilegedGetDeclaredMethods(clazz);
for (Method method : methods)
{
list.add(method.getName());
}
objectMethodNames = list;
}
return objectMethodNames;
}
private static volatile Set 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 do skip bridge methods as they exist for and are handled solely
* by the JVM itself.
*
* 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 getNonPrivateMethods(Class> topClass, boolean excludeFinalMethods)
{
Map> methodMap = new HashMap<>();
List allMethods = new ArrayList<>(10);
Class> clazz = topClass;
if (!clazz.isAnnotation() && clazz.isInterface())
{
addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, clazz);
for (Class> parent : clazz.getInterfaces())
{
addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, parent);
}
}
else
{
while (clazz != null)
{
addNonPrivateMethods(topClass, excludeFinalMethods, methodMap, allMethods, clazz);
clazz = clazz.getSuperclass();
}
}
return allMethods;
}
private static void addNonPrivateMethods(Class> topClass, boolean excludeFinalMethods,
Map> methodMap, List allMethods,
Class> clazz)
{
List temp = new ArrayList<>(Arrays.asList(clazz.getMethods()));
for (Method method : clazz.getDeclaredMethods())
{
if (!temp.contains(method))
{
temp.add(method);
}
}
for (Method method : temp)
{
if (allMethods.contains(method))
{
continue;
}
if (method.isBridge())
{
// we have no interest in generics bridge methods
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 methods = methodMap.get(method.getName());
if (methods == null)
{
methods = new ArrayList<>();
methods.add(method);
allMethods.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);
}
}
}
}
/**
* 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 getAbstractMethods(Class> clazz)
{
if (!Modifier.isAbstract(clazz.getModifiers()))
{
return Collections.emptyList();
}
List methods = getNonPrivateMethods(clazz, true);
if (!methods.isEmpty())
{
Iterator iterator = methods.iterator();
while (iterator.hasNext())
{
if (!Modifier.isAbstract(iterator.next().getModifiers()))
{
iterator.remove();
}
}
}
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
{
return clazz.getMethod(name, parameterTypes) != null;
}
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 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 true
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 ParameterizedType
* else otherwise.
*
* @param type type of the artifact
* @return true if type is an instance of ParameterizedType
*/
public static boolean isParametrizedType(Type type)
{
return type instanceof ParameterizedType;
}
/**
* Returns true if type is an instance of WildcardType
* else otherwise.
*
* @param type type of the artifact
* @return true if type is an instance of WildcardType
*/
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 TypeVariable
* else otherwise.
*
* @param type type of the artifact
* @return true if type is an instance of TypeVariable
*/
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);
Integer 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.
*
* Required type is a wildcard type.
*
* @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 ParameterizedType)
{
ParameterizedType pt = (ParameterizedType)type;
return (Class>)pt.getRawType();
}
else if(type instanceof Class)
{
return (Class>)type;
}
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 superClassMethod
is overridden by subClassMethod
.
* @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);
}
private 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;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy