
com.tangosol.util.fsm.ReflectionHelper Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.util.fsm;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* A collection of utilities to assist in using Reflection to create
* objects.
*
* @author Christer Fahlgren
* @author Brian Oliver
* @since Coherence 12.2.1
*/
public class ReflectionHelper
{
/**
* Get a compatible constructor to the supplied parameter types.
*
* @param clazz the class which we want to construct
* @param parameterTypes the types required of the constructor
*
* @return a compatible constructor or null if none exists
*/
public static Constructor> getCompatibleConstructor(Class> clazz,
Class>[] parameterTypes)
{
Constructor>[] constructors = clazz.getConstructors();
for (int i = 0; i < constructors.length; i++)
{
if (constructors[i].getParameterTypes().length ==
(parameterTypes != null ? parameterTypes.length : 0))
{
// If we have the same number of parameters there is a shot that we have a compatible
// constructor
Class>[] constructorTypes = constructors[i].getParameterTypes();
boolean isCompatible = true;
for (int j = 0; j < (parameterTypes != null ? parameterTypes.length : 0); j++)
{
if (!constructorTypes[j]
.isAssignableFrom(parameterTypes[j]))
{
// The type is not assignment compatible, however
// we might be able to coerce from a basic type to a boxed type
if (constructorTypes[j].isPrimitive())
{
if (!isAssignablePrimitive(constructorTypes[j],
parameterTypes[j]))
{
isCompatible = false;
break;
}
}
}
}
if (isCompatible)
{
return constructors[i];
}
}
}
return null;
}
/**
* Determines if a primitive type is assignable to a wrapper type.
*
* @param clzPrimitive a primitive class type
* @param clzWrapper a wrapper class type
*
* @return true if primitive and wrapper are assignment compatible
*/
public static boolean isAssignablePrimitive(Class> clzPrimitive, Class> clzWrapper)
{
return (clzPrimitive.equals(java.lang.Boolean.TYPE) &&
clzWrapper.equals(java.lang.Boolean.class))
|| (clzPrimitive.equals(java.lang.Byte.TYPE) &&
clzWrapper.equals(java.lang.Byte.class))
|| (clzPrimitive.equals(java.lang.Character.TYPE) &&
clzWrapper.equals(java.lang.Character.class))
|| (clzPrimitive.equals(java.lang.Double.TYPE) &&
clzWrapper.equals(java.lang.Double.class))
|| (clzPrimitive.equals(java.lang.Float.TYPE) &&
clzWrapper.equals(java.lang.Float.class))
|| (clzPrimitive.equals(java.lang.Integer.TYPE) &&
clzWrapper.equals(java.lang.Integer.class))
|| (clzPrimitive.equals(java.lang.Long.TYPE) &&
clzWrapper.equals(java.lang.Long.class))
|| (clzPrimitive.equals(java.lang.Short.TYPE) &&
clzWrapper.equals(java.lang.Short.class));
}
/**
* Obtains the {@link Method} that is compatible to the supplied
* parameter types.
*
* @param clazz the {@link Class} on which to find the {@link Method}
* @param methodName the method name
* @param arguments the arguments for the {@link Method}
*
* @return a compatible {@link Method} or null
if one can't be found
*/
public static Method getCompatibleMethod(Class> clazz, String methodName, Object... arguments)
{
// determine the types of the arguments
Class>[] argumentTypes = new Class>[arguments.length];
for (int i = 0; i < arguments.length; i++)
{
argumentTypes[i] = arguments[i] == null ? null : arguments[i].getClass();
}
try
{
// attempt to find the method on the specified class
// (this may fail, in which case we should try super classes)
return clazz.getDeclaredMethod(methodName, argumentTypes);
}
catch (SecurityException e)
{
return null;
}
catch (NoSuchMethodException e)
{
return clazz.getSuperclass() == null ? null :
getCompatibleMethod(clazz.getSuperclass(), methodName, arguments);
}
}
/**
* Create an Object via reflection (using the specified {@link
* ClassLoader}).
*
* @param sClassName the name of the class to instantiate.
* @param classLoader the {@link ClassLoader} to use to load the class.
*
* @return A new instance of the class specified by the className
*
* @throws ClassNotFoundException if the class is not found
* @throws NoSuchMethodException if there is no such constructor
* @throws InstantiationException if it failed to instantiate
* @throws IllegalAccessException if security doesn't allow the call
* @throws InvocationTargetException if the constructor failed
*/
public static Object createObject(String sClassName, ClassLoader classLoader)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
Class> clazz = Class.forName(sClassName, true, classLoader);
Constructor> con = clazz.getDeclaredConstructor((Class[]) null);
return con.newInstance((Object[]) null);
}
/**
* Create an Object via reflection (using the specified {@link
* ClassLoader}).
*
* @param sClassName the name of the class to instantiate.
* @param constructorParameterList the set of parameters to pass to the constructor
* @param classLoader the {@link ClassLoader} to use to load
* the class.
*
* @return A new instance of the class specified by the className
*
* @throws ClassNotFoundException if the class is not found
* @throws NoSuchMethodException if there is no such constructor
* @throws InstantiationException if it failed to instantiate
* @throws IllegalAccessException if security doesn't allow the call
* @throws InvocationTargetException if the constructor failed
*/
public static Object createObject(String sClassName, Object[] constructorParameterList,
ClassLoader classLoader)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
Class> clazz = Class.forName(sClassName, true, classLoader);
Class>[] parameterTypes = getClassArrayFromObjectArray(constructorParameterList);
Constructor> con = ReflectionHelper .getCompatibleConstructor(clazz, parameterTypes);
return con.newInstance(constructorParameterList);
}
/**
* Returns an array of Class objects representing the class of the
* objects in the parameter.
*
* @param objectArray the array of Objects
*
* @return an array of Classes representing the class of the Objects
*/
protected static Class>[] getClassArrayFromObjectArray(Object[] objectArray)
{
Class>[] parameterTypes = null;
if (objectArray != null)
{
parameterTypes = new Class[objectArray.length];
for (int i = 0; i < objectArray.length; i++)
{
parameterTypes[i] = objectArray[i].getClass();
}
}
return parameterTypes;
}
/**
* Obtains the concrete (non-parameterized) {@link Class} given a specified
* (possibly parameterized) type.
*
* @param type the type
*
* @return the concrete {@link Class} or null
if there is no concrete class.
*/
public static Class> getConcreteType(Type type)
{
if (type instanceof Class)
{
return (Class>) type;
}
else if (type instanceof ParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType) type;
return getConcreteType(parameterizedType.getRawType());
}
else
{
return null;
}
}
/**
* Determines if two types are assignment compatible, that is, the type
* of y can be assigned to type x.
*
* @param x the first type
* @param y the second type
*
* @return if a value of type y is assignable to the type x
*/
public static boolean isAssignableFrom(Type x, Type y)
{
// NOTE: for now we're only supporting compatibility tests using classes
// and parameterized types (but we don't check generics)
if (x instanceof Class && y instanceof Class)
{
Class> clzX = (Class>) x;
Class> clzY = (Class>) y;
return clzX.isAssignableFrom(clzY);
}
else if (x instanceof ParameterizedType && y instanceof Class)
{
return isAssignableFrom(getConcreteType(x), getConcreteType(y));
}
else
{
return false;
}
}
/**
* Determines if the signature of a {@link Method} is compatible with the
* specified parameters.
*
* @param method the {@link Method} to check against
* @param modifiers the desired modifiers of the {@link Method}
* @param returnType the desired return type of the {@link Method}
* @param parameterTypes the parameters to the {@link Method}
*
* @return true
if the {@link Method} signature is
* compatible with the specified parameters, false
* otherwise
*/
public static boolean isCompatibleMethod(Method method, int modifiers,
Type returnType, Type... parameterTypes)
{
// check the parameters first
Type[] methodParameterTypes = method.getGenericParameterTypes();
if (methodParameterTypes.length == parameterTypes.length)
{
for (int i = 0; i < methodParameterTypes.length; i++)
{
if (!isAssignableFrom(methodParameterTypes[i],
parameterTypes[i]))
{
return false;
}
}
return isAssignableFrom(method.getGenericReturnType(),
returnType) && method.getModifiers() == modifiers;
}
else
{
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy