com.alee.utils.ReflectUtils Maven / Gradle / Ivy
The newest version!
/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library. If not, see .
*/
package com.alee.utils;
import com.alee.api.annotations.NotNull;
import com.alee.api.annotations.Nullable;
import com.alee.utils.collection.ImmutableList;
import com.alee.utils.reflection.FieldHelper;
import com.alee.utils.reflection.ModifierType;
import com.alee.utils.reflection.ReflectionException;
import org.slf4j.LoggerFactory;
import java.lang.reflect.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
/**
* This class provides a set of utilities to simplify work with Reflection API.
*
* @author Mikle Garin
*/
public final class ReflectUtils
{
/**
* todo 1. Remove all "safe" methods
* todo 2. Rework this utility class into an object that is only instantiated when needed
* todo 3. Add implemenetation for vararg search
*/
/**
* Whether should allow safe methods to log errors or not.
* By default it is disabled to hide some WebLaF exceptions which occur due to various method checks.
* You can enable it in case you need a deeper look into whats happening here.
*/
private static boolean safeMethodsLoggingEnabled = false;
/**
* Fields lookup cache.
*/
private static final Map> fieldsLookupCache = new HashMap> ();
/**
* Methods lookup cache.
*/
private static final Map> methodsLookupCache = new HashMap> ();
/**
* {@code jdk.internal.loader.BuiltinClassLoader} class available starting from Java 9.
* It's {@code jdk.internal.loader.ClassLoaders.AppClassLoader} extension is used as default application {@link ClassLoader}.
*/
private static final String JAVA9_BUILT_IN_CLASS_LOADER = "jdk.internal.loader.BuiltinClassLoader";
/**
* Private constructor to avoid instantiation.
*/
private ReflectUtils ()
{
throw new UtilityException ( "Utility classes are not meant to be instantiated" );
}
/**
* Returns whether should allow safe methods to log errors or not.
*
* @return {@code true} if should allow safe methods to log errors, {@code false} otherwise
*/
public static boolean isSafeMethodsLoggingEnabled ()
{
return safeMethodsLoggingEnabled;
}
/**
* Sets whether should allow safe methods to log errors or not.
*
* @param enabled whether should allow safe methods to log errors or not
*/
public static void setSafeMethodsLoggingEnabled ( final boolean enabled )
{
ReflectUtils.safeMethodsLoggingEnabled = enabled;
}
/**
* Returns class for the specified canonical name.
*
* @param canonicalName class canonical name
* @param class type
* @return class for the specified canonical name
*/
@Nullable
public static Class getClassSafely ( @NotNull final String canonicalName )
{
try
{
return getClass ( canonicalName );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getClassSafely ( %s )";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( String.format ( msg, canonicalName ), e );
}
return null;
}
}
/**
* Returns class for the specified canonical name.
*
* @param canonicalName class canonical name
* @param class type
* @return class for the specified canonical name
* @throws ClassNotFoundException if class was not found
*/
@NotNull
public static Class getClass ( @NotNull final String canonicalName ) throws ClassNotFoundException
{
return ( Class ) Class.forName ( canonicalName );
}
/**
* Returns inner class with the specified name.
*
* @param fromClass class to look for the inner class
* @param innerClassName inner class name
* @param inner class type
* @return inner class with the specified name
*/
public static Class getInnerClassSafely ( final Class fromClass, final String innerClassName )
{
return getInnerClassSafely ( fromClass.getCanonicalName (), innerClassName );
}
/**
* Returns inner class with the specified name.
*
* @param fromClassName name of the class to look for the inner class
* @param innerClassName inner class name
* @param inner class type
* @return inner class with the specified name
*/
public static Class getInnerClassSafely ( final String fromClassName, final String innerClassName )
{
try
{
return getInnerClass ( fromClassName, innerClassName );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getInnerClassSafely ( %s, %s )";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( String.format ( msg, fromClassName, innerClassName ), e );
}
return null;
}
}
/**
* Returns inner class with the specified name.
*
* @param fromClass class to look for the inner class
* @param innerClassName inner class name
* @param inner class type
* @return inner class with the specified name
* @throws ClassNotFoundException if inner class was not found
*/
public static Class getInnerClass ( final Class fromClass, final String innerClassName ) throws ClassNotFoundException
{
return getInnerClass ( fromClass.getCanonicalName (), innerClassName );
}
/**
* Returns inner class with the specified name.
*
* @param fromClassName name of the class to look for the inner class
* @param innerClassName inner class name
* @param inner class type
* @return inner class with the specified name
* @throws ClassNotFoundException if inner class was not found
*/
public static Class getInnerClass ( final String fromClassName, final String innerClassName ) throws ClassNotFoundException
{
return getClass ( fromClassName + "$" + innerClassName );
}
/**
* Returns method caller class.
* It is not recommended to use this method anywhere but in debugging.
*
* @return method caller class
*/
public static Class getCallerClass ()
{
// We have to add one to depth since this method call is increasing it
return getCallerClass ( 1 );
}
/**
* Returns method caller class.
* It is not recommended to use this method anywhere but in debugging.
*
* @param additionalDepth additional methods depth
* @return method caller class
*/
public static Class getCallerClass ( final int additionalDepth )
{
// Depth explanation:
// 0 - this method class
// 1 - this method caller class
// 2 - caller's class caller
// additionalDepth - in case call goes through additional methods this is required
final int depth = 2 + additionalDepth;
try
{
// We add additional 3 levels of depth due to reflection calls here
return callStaticMethod ( "sun.reflect.Reflection", "getCallerClass", depth + 3 );
}
catch ( final Exception e )
{
try
{
// Simply use determined depth
return getClass ( new Throwable ().getStackTrace ()[ depth ].getClassName () );
}
catch ( final ClassNotFoundException ex )
{
return null;
}
}
}
/**
* Returns all fields in the specified object class and all of its superclasses.
*
* @param object object to find fields for
* @return all fields in the specified object class and all of its superclasses
*/
public static List getFields ( final Object object )
{
return getFields ( object.getClass () );
}
/**
* Returns all fields in the specified class and all of its superclasses.
*
* @param clazz class to find fields for
* @return all fields in the specified class and all of its superclasses
*/
public static List getFields ( final Class clazz )
{
return getFields ( clazz, ModifierType.STATIC );
}
/**
* Returns all fields in the specified object class and all of its superclasses.
*
* @param object object to find fields for
* @param ignoredModifiers modifiers of fields to ignore
* @return all fields in the specified object class and all of its superclasses
*/
public static List getFields ( final Object object, final ModifierType... ignoredModifiers )
{
return getFields ( object.getClass (), ignoredModifiers );
}
/**
* Returns all fields in the specified class and all of its superclasses.
*
* @param clazz class to find fields for
* @param ignoredModifiers modifiers of fields to ignore
* @return all fields in the specified class and all of its superclasses
*/
public static List getFields ( final Class clazz, final ModifierType... ignoredModifiers )
{
return getFields ( clazz, new HashSet (), ignoredModifiers );
}
/**
* Returns all fields in the specified class and all of its superclasses.
*
* @param clazz class to find fields for
* @param found found field names
* @param ignoredModifiers modifiers of fields to ignore
* @return all fields in the specified class and all of its superclasses
*/
private static List getFields ( final Class clazz, final Set found, final ModifierType... ignoredModifiers )
{
// Find all current-level fields
final Field[] declared = clazz.getDeclaredFields ();
final List fields = new ArrayList ( declared.length );
for ( final Field field : declared )
{
// Adding fields with unique name that haven't been found yet (on higher hierarchy levels)
// and that do not contain any modifiers from the ignore list passed into this methos
if ( !found.contains ( field.getName () ) && ReflectUtils.hasNoneOfModifiers ( field, ignoredModifiers ) )
{
// Making field accessible for usage convenience
field.setAccessible ( true );
// Collecting field
fields.add ( field );
// Marking unique field name as used
// This is important to avoid overwriting fields with ones from parent classes (with the same name)
found.add ( field.getName () );
}
}
// Find all superclass fields
final Class superclass = clazz.getSuperclass ();
if ( superclass != null )
{
fields.addAll ( getFields ( superclass, found, ignoredModifiers ) );
}
return fields;
}
/**
* Returns whether or not {@link Class} has any of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Class clazz, final ModifierType... modifiers )
{
return hasAnyOfModifiers ( clazz, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Class} has any of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Class clazz, final Collection modifiers )
{
boolean contains = false;
if ( CollectionUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.is ( clazz ) )
{
contains = true;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Class} has all of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Class clazz, final ModifierType... modifiers )
{
return hasAllOfModifiers ( clazz, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Class} has all of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Class clazz, final Collection modifiers )
{
boolean contains = true;
if ( ArrayUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.not ( clazz ) )
{
contains = false;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Class} has none of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Class clazz, final ModifierType... modifiers )
{
return hasNoneOfModifiers ( clazz, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Class} has none of the specified modifiers.
*
* @param clazz {@link Class} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Class} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Class clazz, final Collection modifiers )
{
return !hasAnyOfModifiers ( clazz, modifiers );
}
/**
* Returns whether or not {@link Method} has any of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Method method, final ModifierType... modifiers )
{
return hasAnyOfModifiers ( method, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Method} has any of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Method method, final Collection modifiers )
{
boolean contains = false;
if ( CollectionUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.is ( method ) )
{
contains = true;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Method} has all of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Method method, final ModifierType... modifiers )
{
return hasAllOfModifiers ( method, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Method} has all of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Method method, final Collection modifiers )
{
boolean contains = true;
if ( ArrayUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.not ( method ) )
{
contains = false;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Method} has none of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Method method, final ModifierType... modifiers )
{
return hasNoneOfModifiers ( method, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Method} has none of the specified modifiers.
*
* @param method {@link Method} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Method} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Method method, final Collection modifiers )
{
return !hasAnyOfModifiers ( method, modifiers );
}
/**
* Returns whether or not {@link Field} has any of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Field field, final ModifierType... modifiers )
{
return hasAnyOfModifiers ( field, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Field} has any of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has any of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAnyOfModifiers ( final Field field, final Collection modifiers )
{
boolean contains = false;
if ( CollectionUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.is ( field ) )
{
contains = true;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Field} has all of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Field field, final ModifierType... modifiers )
{
return hasAllOfModifiers ( field, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Field} has all of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has all of the specified modifiers, {@code false} otherwise
*/
public static boolean hasAllOfModifiers ( final Field field, final Collection modifiers )
{
boolean contains = true;
if ( ArrayUtils.notEmpty ( modifiers ) )
{
for ( final ModifierType modifier : modifiers )
{
if ( modifier.not ( field ) )
{
contains = false;
break;
}
}
}
return contains;
}
/**
* Returns whether or not {@link Field} has none of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Field field, final ModifierType... modifiers )
{
return hasNoneOfModifiers ( field, new ImmutableList ( modifiers ) );
}
/**
* Returns whether or not {@link Field} has none of the specified modifiers.
*
* @param field {@link Field} to check modifiers for
* @param modifiers modifiers to look for
* @return {@code true} if {@link Field} has none of the specified modifiers, {@code false} otherwise
*/
public static boolean hasNoneOfModifiers ( final Field field, final Collection modifiers )
{
return !hasAnyOfModifiers ( field, modifiers );
}
/**
* Returns specified class field.
* This method will also look for the field in super-classes if any exist.
*
* @param classType type of the class where field can be located
* @param fieldName field name
* @return specified class field
*/
@Nullable
public static Field getFieldSafely ( @NotNull final Class classType, @NotNull final String fieldName )
{
Field field = null;
try
{
field = getField ( classType, fieldName );
}
catch ( final NoSuchFieldException e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getFieldSafely ( %s, %s )";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( String.format ( msg, classType, fieldName ), e );
}
}
return field;
}
/**
* Returns specified class field.
* If field is not found in the object class all superclasses will be searched for that field.
* This method will also find {@code protected}, {@code private} and package local fields.
*
* @param classType type of the class where field can be located
* @param fieldName field name
* @return specified class field
* @throws NoSuchFieldException if field was not found
*/
@NotNull
public static Field getField ( @NotNull final Class> classType, @NotNull final String fieldName ) throws NoSuchFieldException
{
// Field key
final String canonicalName = classType.getCanonicalName ();
final String key = canonicalName + "." + fieldName;
// Checking cache existence
Field field = null;
Map classFieldsCache = fieldsLookupCache.get ( classType );
if ( classFieldsCache != null )
{
field = classFieldsCache.get ( key );
}
else
{
classFieldsCache = new HashMap ( 1 );
fieldsLookupCache.put ( classType, classFieldsCache );
}
// Updating cache
if ( field == null )
{
// Trying to retrieve field from class or one of its superclasses
field = getFieldImpl ( classType, fieldName );
// Trying to retrieve static field from interface
if ( field == null )
{
field = getInterfaceFieldImpl ( classType, fieldName );
}
// Checking field existence
if ( field != null )
{
field.setAccessible ( true );
}
else
{
final String msg = "Field '%s' not found in class: %s";
throw new NoSuchFieldException ( String.format ( msg, fieldName, canonicalName ) );
}
// Caching field
classFieldsCache.put ( key, field );
}
return field;
}
/**
* Returns specified class field.
* This method will also look for the field in super-classes if any exist.
*
* @param classType type of the class where field can be located
* @param fieldName field name
* @return specified class field
*/
private static Field getFieldImpl ( final Class classType, final String fieldName )
{
Field field;
try
{
field = classType.getDeclaredField ( fieldName );
}
catch ( final NoSuchFieldException e )
{
final Class superclass = classType.getSuperclass ();
field = superclass != null ? getFieldImpl ( superclass, fieldName ) : null;
}
return field;
}
/**
* Returns specified class interface static field.
* This method will also look for the field in super-class interfaces if any exist.
*
* @param classType type of the interface where field can be located
* @param fieldName field name
* @return specified class interface static field
*/
private static Field getInterfaceFieldImpl ( final Class classType, final String fieldName )
{
Field field = null;
if ( classType.isInterface () )
{
final Field[] fields = classType.getDeclaredFields ();
for ( final Field f : fields )
{
if ( f.getName ().equals ( fieldName ) )
{
field = f;
break;
}
}
}
if ( field == null )
{
final Class[] interfaces = classType.getInterfaces ();
for ( final Class iface : interfaces )
{
field = getInterfaceFieldImpl ( iface, fieldName );
if ( field != null )
{
break;
}
}
}
if ( field == null )
{
final Class superclass = classType.getSuperclass ();
field = superclass != null ? getInterfaceFieldImpl ( superclass, fieldName ) : null;
}
return field;
}
/**
* Returns specified class field's type.
* This method will also look for the field in super-classes if any exist.
*
* @param classType type of the class where field can be located
* @param fieldName field name
* @return specified class field's type
*/
public static Class> getFieldTypeSafely ( final Class classType, final String fieldName )
{
try
{
return getFieldType ( classType, fieldName );
}
catch ( final NoSuchFieldException e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getFieldTypeSafely ( %s, %s )";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( String.format ( msg, classType, fieldName ), e );
}
return null;
}
}
/**
* Returns specified class field's type.
* This method will also look for the field in super-classes if any exist.
*
* @param classType type of the class where field can be located
* @param fieldName field name
* @return specified class field's type
* @throws NoSuchFieldException if field was not found
*/
public static Class> getFieldType ( final Class classType, final String fieldName ) throws NoSuchFieldException
{
return getField ( classType, fieldName ).getType ();
}
/**
* Applies specified value to object field.
* This method allows to access and modify even private fields.
*
* @param object object instance
* @param field object field
* @param value field value
* @return {@code true} if value was applied successfully, {@code false} otherwise
*/
public static boolean setFieldValueSafely ( final Object object, final String field, final Object value )
{
try
{
setFieldValue ( object, field, value );
return true;
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: setFieldValueSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return false;
}
}
/**
* Applies specified value to object field.
* This method allows to access and modify even private fields.
*
* @param object object instance
* @param fieldName object field name
* @param value field value
* @throws NoSuchFieldException if field was not found
* @throws IllegalAccessException if field is inaccessible
*/
public static void setFieldValue ( final Object object, final String fieldName, final Object value )
throws NoSuchFieldException, IllegalAccessException
{
// Retrieving actual field
final Field actualField = getField ( object.getClass (), fieldName );
// Applying field value
setFieldValue ( object, actualField, value );
}
/**
* Applies specified value to static class field.
* This method allows to access and modify even private fields.
*
* @param classType type of the class where static field can be located
* @param field object field
* @param value field value
* @return {@code true} if value was applied successfully, {@code false} otherwise
*/
public static boolean setStaticFieldValueSafely ( final Class classType, final String field, final Object value )
{
try
{
setStaticFieldValue ( classType, field, value );
return true;
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: setFieldValueSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return false;
}
}
/**
* Applies specified value to static class field.
* This method allows to access and modify even private fields.
*
* @param classType type of the class where static field can be located
* @param fieldName object field name
* @param value field value
* @throws NoSuchFieldException if field was not found
* @throws IllegalAccessException if field is inaccessible
*/
public static void setStaticFieldValue ( final Class classType, final String fieldName, final Object value )
throws NoSuchFieldException, IllegalAccessException
{
// Retrieving actual field
final Field actualField = getField ( classType, fieldName );
// Applying field value
setFieldValue ( null, actualField, value );
}
/**
* Applies specified value to object field.
* This method allows to access and modify even private object fields.
*
* @param object object instance
* @param field object field
* @param value field value
* @return {@code true} if value was applied successfully, {@code false} otherwise
*/
public static boolean setFieldValueSafely ( final Object object, final Field field, final Object value )
{
try
{
setFieldValue ( object, field, value );
return true;
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: setFieldValueSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return false;
}
}
/**
* Applies specified value to object field.
* This method allows to access and modify even private object fields.
*
* @param object object instance
* @param field object field
* @param value field value
* @throws IllegalAccessException if field is inaccessible
*/
public static void setFieldValue ( final Object object, final Field field, final Object value )
throws IllegalAccessException
{
// Making field accessible
if ( !field.isAccessible () )
{
field.setAccessible ( true );
}
// Removing final modifier if needed
final int oldModifiers = field.getModifiers ();
if ( ModifierType.FINAL.is ( oldModifiers ) )
{
// todo This shouldn't really be called ever by WebLaF itself under normal circumstances
FieldHelper.setFieldModifiers ( field, oldModifiers & ~Modifier.FINAL );
}
// Updating field value
field.set ( object, value );
// Restoring final modifier if it was removed
if ( ModifierType.FINAL.is ( oldModifiers ) )
{
FieldHelper.setFieldModifiers ( field, oldModifiers );
}
}
/**
* Returns object field value.
* This method allows to access even private object fields.
*
* @param object object instance
* @param fieldName object field name
* @param field value type
* @return object field value
*/
public static T getFieldValueSafely ( final Object object, final String fieldName )
{
try
{
return getFieldValue ( object, fieldName );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getFieldValueSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns object field value.
* This method allows to access even private object fields.
*
* @param object object instance
* @param fieldName object field name
* @param field value type
* @return object field value
* @throws NoSuchFieldException if field was not found
* @throws IllegalAccessException if field is inaccessible
*/
public static T getFieldValue ( final Object object, final String fieldName ) throws NoSuchFieldException, IllegalAccessException
{
final Field actualField = getField ( object.getClass (), fieldName );
ModifierType.STATIC.checkNot ( actualField );
return ( T ) actualField.get ( object );
}
/**
* Returns static field value from the specified class.
*
* @param classType class type
* @param fieldName class field name
* @param returned value type
* @return static field value from the specified class
*/
public static T getStaticFieldValueSafely ( final Class classType, final String fieldName )
{
try
{
return getStaticFieldValue ( classType, fieldName );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getStaticFieldValueSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns static field value from the specified class.
*
* @param classType class type
* @param fieldName class field name
* @param returned value type
* @return static field value from the specified class
* @throws NoSuchFieldException if field was not found
* @throws IllegalAccessException if field is inaccessible
*/
public static T getStaticFieldValue ( final Class classType, final String fieldName )
throws NoSuchFieldException, IllegalAccessException
{
final Field actualField = getField ( classType, fieldName );
ModifierType.STATIC.check ( actualField );
return ( T ) actualField.get ( null );
}
/**
* Returns class name with ".java" extension in the end.
*
* @param classObject object of class type
* @return class name with ".java" extension in the end
*/
@NotNull
public static String getJavaClassName ( @NotNull final Object classObject )
{
return getJavaClassName ( classObject.getClass () );
}
/**
* Returns class name with ".java" extension in the end.
*
* @param classType class type
* @return class name with ".java" extension in the end
*/
@NotNull
public static String getJavaClassName ( @NotNull final Class classType )
{
return getClassName ( classType ) + ".java";
}
/**
* Returns class name with ".class" extension in the end.
*
* @param classObject object of class type
* @return class name with ".class" extension in the end
*/
@NotNull
public static String getClassFileName ( @NotNull final Object classObject )
{
return getClassFileName ( classObject.getClass () );
}
/**
* Returns class name with ".class" extension in the end.
*
* @param classType class type
* @return class name with ".class" extension in the end
*/
@NotNull
public static String getClassFileName ( @NotNull final Class classType )
{
return ReflectUtils.getClassName ( classType ) + ".class";
}
/**
* Returns class name.
*
* @param classObject object of class type
* @return class name
*/
@NotNull
public static String getClassName ( @NotNull final Object classObject )
{
return getClassName ( classObject.getClass () );
}
/**
* Returns class name.
*
* @param classType class type
* @return class name
*/
@NotNull
public static String getClassName ( @NotNull final Class classType )
{
final String canonicalName = classType.getCanonicalName ();
final String fullName = canonicalName != null ? canonicalName : classType.toString ();
final int dot = fullName.lastIndexOf ( "." );
return dot != -1 ? fullName.substring ( dot + 1 ) : fullName;
}
/**
* Returns complete class name that includes enclosing class name if one exists.
*
* @param classObject object of class type
* @return complete class name that includes enclosing class name if one exists
*/
@NotNull
public static String getCompleteClassName ( @NotNull final Object classObject )
{
return getCompleteClassName ( classObject.getClass () );
}
/**
* Returns complete class name that includes enclosing class name if one exists.
*
* @param classType class type
* @return complete class name that includes enclosing class name if one exists
*/
@NotNull
public static String getCompleteClassName ( @NotNull final Class classType )
{
final String name = getClassName ( classType );
final Class enclosingClass = classType.getEnclosingClass ();
return enclosingClass != null ? getCompleteClassName ( enclosingClass ) + "$" + name : name;
}
/**
* Returns class packages.
*
* @param classObject object of class type
* @return class packages
*/
public static String[] getClassPackages ( final Object classObject )
{
return getClassPackages ( classObject.getClass () );
}
/**
* Returns class packages.
*
* @param classType class type
* @return class packages
*/
public static String[] getClassPackages ( final Class classType )
{
return getPackages ( classType.getPackage ().getName () );
}
/**
* Returns packages names.
*
* @param packageName package name
* @return packages names
*/
public static String[] getPackages ( final String packageName )
{
return packageName.split ( "\\." );
}
/**
* Returns newly created class instance.
*
* @param canonicalClassName canonical class name
* @param arguments class constructor arguments
* @param class instance type
* @return newly created class instance
*/
public static T createInstanceSafely ( final String canonicalClassName, final Object... arguments )
{
try
{
return createInstance ( canonicalClassName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: createInstanceSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns newly created class instance.
*
* @param canonicalClassName canonical class name
* @param arguments class constructor arguments
* @param class instance type
* @return newly created class instance
* @throws ClassNotFoundException if class was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
* @throws InstantiationException if the class is abstract
* @throws NoSuchMethodException if method was not found
*/
public static T createInstance ( final String canonicalClassName, final Object... arguments )
throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException
{
return createInstance ( loadClass ( canonicalClassName ), arguments );
}
/**
* Returns newly created class instance.
*
* @param theClass class to process
* @param arguments class constructor arguments
* @param class instance type
* @return newly created class instance
*/
public static T createInstanceSafely ( final Class theClass, final Object... arguments )
{
try
{
return createInstance ( theClass, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: createInstanceSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns newly created class instance.
*
* @param theClass class to process
* @param arguments class constructor arguments
* @param class instance type
* @return newly created class instance
* @throws InstantiationException if the class is abstract
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
public static T createInstance ( final Class theClass, final Object... arguments )
throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
// Retrieving argument types
final Class[] parameterTypes = getClassTypes ( arguments );
// Retrieving constructor
final Constructor constructor = getConstructor ( theClass, parameterTypes );
// Creating new instance
return ( T ) constructor.newInstance ( arguments );
}
/**
* Returns class constructor for the specified argument types.
* This method will also find {@code protected}, {@code private} and package local constructors.
*
* todo 1. Constructors priority check (by super types)
* todo Right now some constructor with [Object] arg might be used instead of constructor with [String]
* todo To avoid issues don't call constructors with same amount of arguments and which are cast-able to each other
* todo 2. Vararg constructors might not be found in many cases
* todo Additional checks/workarounds for such constructors should be added to avoid issues
*
* @param theClass class to process
* @param parameterTypes constructor argument types
* @return class constructor for the specified argument types
* @throws NoSuchMethodException if constructor was not found
*/
public static Constructor getConstructor ( final Class theClass, final Class... parameterTypes ) throws NoSuchMethodException
{
// This enhancement is a bad idea since protected/private constructor it won't be found
/*// Simplified constructor search for empty parameters
if ( parameterTypes.length == 0 )
{
return theClass.getConstructor ();
}*/
// This enhancement is a bad idea as it will return appropriate inner class constructor
// but you will surely be disoriented outside of this call why you have an extra parement
// and generally you won't be able to properly instantiate it without additional workarounds
/*// Workaround for simplifying inner classes constructor retrieval
final Class[] actualParameterTypes;
if ( theClass.isMemberClass () && ModifierType.STATIC.not ( theClass ) )
{
actualParameterTypes = new Class[ parameterTypes.length + 1 ];
actualParameterTypes[ 0 ] = theClass.getEnclosingClass ();
System.arraycopy ( parameterTypes, 0, actualParameterTypes, 1, parameterTypes.length );
}
else
{
actualParameterTypes = parameterTypes;
}*/
// Special check for inner classes
if ( theClass.isMemberClass () && ModifierType.STATIC.not ( theClass ) )
{
// Ensure first parameter is a type compatible with class enclosing specified inner class
if ( parameterTypes.length == 0 )
{
// No parameters at all, it seems caller is not aware it is asking to find inner class constructor
throw new ReflectionException ( "Enclosing class paramter for inner class constructor is missing" );
}
else if ( !isAssignable ( theClass.getEnclosingClass (), parameterTypes[ 0 ] ) )
{
// Inner's class enclosing class is not assignable from first parameter type
throw new ReflectionException ( "Incorrect first parameter for inner class constructor" );
}
}
// Constructors can be used only from the topmost class so we don't need to look for them in superclasses
for ( final Constructor constructor : theClass.getDeclaredConstructors () )
{
// Retrieving constructor parameter types
final Class[] types = constructor.getParameterTypes ();
// Checking some simple cases first
if ( types.length != parameterTypes.length )
{
// Inappropriate constructor
continue;
}
else if ( types.length == 0 )
{
// Constructor with no parameters
constructor.setAccessible ( true );
return constructor;
}
// Checking parameter types
boolean fits = true;
for ( int i = 0; i < types.length; i++ )
{
if ( !isAssignable ( types[ i ], parameterTypes[ i ] ) )
{
fits = false;
break;
}
}
if ( fits )
{
constructor.setAccessible ( true );
return constructor;
}
}
// Throwing proper exception that constructor was not found
throw new NoSuchMethodException ( "Constructor was not found: " +
theClass.getCanonicalName () + argumentTypesToString ( parameterTypes ) );
}
/**
* Returns result of called static method.
* Will return null in case method is void-type.
*
* @param canonicalClassName canonical class name
* @param methodName static method name
* @param arguments method arguments
* @param method result type
* @return result of called static method
*/
public static T callStaticMethodSafely ( final String canonicalClassName, final String methodName, final Object... arguments )
{
try
{
return callStaticMethod ( canonicalClassName, methodName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: callStaticMethodSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns result of called static method.
* Will return null in case method is void-type.
*
* @param canonicalClassName canonical class name
* @param methodName static method name
* @param arguments method arguments
* @param method result type
* @return result of called static method
* @throws ClassNotFoundException if class was not found
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
public static T callStaticMethod ( final String canonicalClassName, final String methodName, final Object... arguments )
throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException
{
return callStaticMethod ( getClass ( canonicalClassName ), methodName, arguments );
}
/**
* Returns result of called static method.
* Will return null in case method is void-type.
*
* @param theClass class to process
* @param methodName static method name
* @param arguments method arguments
* @param method result type
* @return result of called static method
*/
public static T callStaticMethodSafely ( final Class theClass, final String methodName, final Object... arguments )
{
try
{
return callStaticMethod ( theClass, methodName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: callStaticMethodSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns result of called static method.
* Will return null in case method is void-type.
*
* @param theClass class to process
* @param methodName static method name
* @param arguments static method arguments
* @param method result type
* @return result given by called static method
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
public static T callStaticMethod ( final Class theClass, final String methodName, final Object... arguments )
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
final Method method = getMethod ( theClass, methodName, arguments );
return ( T ) method.invoke ( null, arguments );
}
/**
* Returns list of results returned by called methods.
*
* @param objects objects to call methods on
* @param methodName method name
* @param arguments method arguments
* @param method result type
* @return list of results returned by called methods
*/
@NotNull
public static List callMethodsSafely ( @NotNull final List> objects, @NotNull final String methodName,
@NotNull final Object... arguments )
{
final List results = new ArrayList ();
for ( final Object object : objects )
{
try
{
results.add ( ( T ) callMethod ( object, methodName, arguments ) );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: callMethodsSafely:callMethod";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
results.add ( null );
}
}
return results;
}
/**
* Returns list of results returned by called methods.
*
* @param objects objects to call methods on
* @param methodName method name
* @param arguments method arguments
* @param method result type
* @return list of results returned by called methods
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
@NotNull
public static List callMethods ( @NotNull final List> objects, @NotNull final String methodName,
@NotNull final Object... arguments )
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
final List results = new ArrayList ();
for ( final Object object : objects )
{
results.add ( ( T ) callMethod ( object, methodName, arguments ) );
}
return results;
}
/**
* Returns an array of results returned by called methods.
*
* @param objects objects to call methods on
* @param methodName method name
* @param arguments method arguments
* @return an array of results returned by called methods
*/
@NotNull
public static Object[] callMethodsSafely ( @NotNull final Object[] objects, @NotNull final String methodName,
@NotNull final Object... arguments )
{
final Object[] results = new Object[ objects.length ];
for ( int i = 0; i < objects.length; i++ )
{
try
{
results[ i ] = callMethod ( objects[ i ], methodName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: callMethodsSafely:callMethod";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
results[ i ] = null;
}
}
return results;
}
/**
* Returns an array of results returned by called methods.
*
* @param objects objects to call methods on
* @param methodName method name
* @param arguments method arguments
* @return an array of results returned by called methods
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
@NotNull
public static Object[] callMethods ( @NotNull final Object[] objects, @NotNull final String methodName,
@NotNull final Object... arguments )
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
final Object[] results = new Object[ objects.length ];
for ( int i = 0; i < objects.length; i++ )
{
results[ i ] = callMethod ( objects[ i ], methodName, arguments );
}
return results;
}
/**
* Returns result given by called method.
*
* @param object object instance
* @param methodName method name
* @param arguments method arguments
* @param method result type
* @return result given by called method
*/
@Nullable
public static T callMethodSafely ( @NotNull final Object object, @NotNull final String methodName,
@NotNull final Object... arguments )
{
T result;
try
{
result = callMethod ( object, methodName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: callMethodSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
result = null;
}
return result;
}
/**
* Calls object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
* Returns result given by called method.
*
* @param object object instance
* @param methodName method name
* @param arguments method arguments
* @param method result type
* @return result given by called method
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
* @throws ExceptionInInitializerError if the initialization provoked by this method fails
*/
@Nullable
public static T callMethod ( @NotNull final Object object, @NotNull final String methodName, @NotNull final Object... arguments )
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
final Method method = getMethod ( object.getClass (), methodName, arguments );
return ( T ) method.invoke ( object, arguments );
}
/**
* Returns field getter method by popular method naming pattern.
* Basically those are "getFieldName"-like and "isFieldName"-like method names.
*
* @param object object
* @param field field name
* @return field getter method by popular method naming pattern
*/
public static Method getFieldGetter ( final Object object, final String field )
{
return getFieldGetter ( object.getClass (), field );
}
/**
* Returns field getter method by popular method naming pattern.
* Basically those are "getFieldName"-like and "isFieldName"-like method names.
*
* @param aClass object class
* @param field field name
* @return field getter method by popular method naming pattern
*/
public static Method getFieldGetter ( final Class aClass, final String field )
{
// Look for "get" method
final Method get = getMethodSafely ( aClass, getGetterMethodName ( field ) );
if ( get != null )
{
// Return "get" method
return get;
}
else
{
// Return "is" method
return getMethodSafely ( aClass, getIsGetterMethodName ( field ) );
}
}
/**
* Returns setter method name for the specified field.
*
* @param field field name
* @return setter method name for the specified field
*/
public static String getSetterMethodName ( final String field )
{
return "set" + field.substring ( 0, 1 ).toUpperCase ( Locale.ROOT ) + field.substring ( 1 );
}
/**
* Returns getter method name for the specified field.
*
* @param field field name
* @return getter method name for the specified field
*/
public static String getGetterMethodName ( final String field )
{
return "get" + field.substring ( 0, 1 ).toUpperCase ( Locale.ROOT ) + field.substring ( 1 );
}
/**
* Returns "is" getter method name for the specified field.
*
* @param field field name
* @return "is" getter method name for the specified field
*/
public static String getIsGetterMethodName ( final String field )
{
return "is" + field.substring ( 0, 1 ).toUpperCase ( Locale.ROOT ) + field.substring ( 1 );
}
/**
* Returns whether method with the specified name and arguments exists in the specified object.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param object object
* @param methodName method name
* @param arguments method arguments
* @return {@code true} if method with the specified name and arguments exists in the specified object, {@code false} otherwise
*/
public static boolean hasMethod ( @NotNull final Object object, @NotNull final String methodName, @NotNull final Object... arguments )
{
return hasMethod ( object.getClass (), methodName, arguments );
}
/**
* Returns whether method with the specified name and arguments exists in the specified class.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param aClass object class
* @param methodName method name
* @param arguments method arguments
* @return {@code true} if method with the specified name and arguments exists in the specified class, {@code false} otherwise
*/
public static boolean hasMethod ( @NotNull final Class aClass, @NotNull final String methodName, @NotNull final Object... arguments )
{
boolean result;
try
{
result = getMethod ( aClass, methodName, arguments ) != null;
}
catch ( final Exception e )
{
result = false;
}
return result;
}
/**
* Calls object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
* Returns result given by called method.
*
* @param object object
* @param methodName method name
* @param arguments method arguments
* @return result given by called method
*/
public static Method getMethodSafely ( final Object object, final String methodName, final Object... arguments )
{
return getMethodSafely ( object.getClass (), methodName, arguments );
}
/**
* Returns object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param aClass object class
* @param methodName method name
* @param arguments method arguments
* @return object's method with the specified name and arguments
*/
public static Method getMethodSafely ( final Class aClass, final String methodName, final Object... arguments )
{
try
{
return getMethod ( aClass, methodName, arguments );
}
catch ( final Exception e )
{
if ( safeMethodsLoggingEnabled )
{
final String msg = "ReflectionUtils method failed: getMethodSafely";
LoggerFactory.getLogger ( ReflectUtils.class ).error ( msg, e );
}
return null;
}
}
/**
* Returns object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param object object
* @param methodName method name
* @param arguments method arguments
* @return object's method with the specified name and arguments
* @throws NoSuchMethodException if method was not found
*/
public static Method getMethod ( final Object object, final String methodName, final Object... arguments )
throws NoSuchMethodException
{
return getMethod ( object.getClass (), methodName, arguments );
}
/**
* Returns object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
* This method will also find {@code protected}, {@code private} and package local methods.
*
* todo 1. Methods priority check (by super types)
* todo Right now some method with [Object] arg might be used instead of method with [String]
* todo To avoid issues don't call methods with same amount of arguments and which are cast-able to each other
* todo 2. Vararg methods might not be found in many cases
* todo Additional checks/workarounds for such methods should be added to avoid issues
*
* @param aClass object class
* @param methodName method name
* @param arguments method arguments
* @return object's method with the specified name and arguments
* @throws NoSuchMethodException if method was not found
*/
public static Method getMethod ( @NotNull final Class aClass, @NotNull final String methodName, @NotNull final Object... arguments )
throws NoSuchMethodException
{
// Method key
final Class[] classTypes = getClassTypes ( arguments );
final String key = aClass.getCanonicalName () + "." + methodName + argumentTypesToString ( classTypes );
// Checking cache
Method method = null;
Map classMethodsCache = methodsLookupCache.get ( aClass );
if ( classMethodsCache != null )
{
method = classMethodsCache.get ( key );
}
else
{
classMethodsCache = new HashMap ( 1 );
methodsLookupCache.put ( aClass, classMethodsCache );
}
// Updating cache
if ( method == null )
{
method = getMethodImpl ( aClass, methodName, arguments );
classMethodsCache.put ( key, method );
}
return method;
}
/**
* Returns object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param aClass object class
* @param methodName method name
* @param arguments method arguments
* @return object's method with the specified name and arguments
* @throws NoSuchMethodException if method was not found
*/
private static Method getMethodImpl ( final Class aClass, final String methodName, final Object[] arguments )
throws NoSuchMethodException
{
// This enhancement was a bad idea and was disabled
// In case method is protected/private or located in one of superclasses it won't be found
// if ( arguments.length == 0 )
// {
// // Searching simple method w/o arguments
// method = aClass.getMethod ( methodName );
// method.setAccessible ( true );
// }
// Searching for more complex method
final Class[] types = getClassTypes ( arguments );
return getMethodImpl ( aClass, aClass, methodName, types );
}
/**
* Returns object's method with the specified name and arguments.
* If method is not found in the object class all superclasses will be searched for that method.
*
* @param topClass initial object class
* @param currentClass object class we are looking in for the method
* @param methodName method name
* @param types method argument types
* @return object's method with the specified name and arguments
* @throws NoSuchMethodException if method was not found
*/
private static Method getMethodImpl ( final Class topClass, final Class currentClass, final String methodName, final Class[] types )
throws NoSuchMethodException
{
// Searching for the specified method in object's class or one of its superclasses
for ( final Method method : currentClass.getDeclaredMethods () )
{
// Checking method name
if ( method.getName ().equals ( methodName ) )
{
// Checking method arguments count
final Class>[] mt = method.getParameterTypes ();
if ( mt.length == types.length )
{
// Checking that arguments fit
boolean fits = true;
for ( int i = 0; i < mt.length; i++ )
{
if ( !isAssignable ( mt[ i ], types[ i ] ) )
{
fits = false;
break;
}
}
if ( fits )
{
// Returning found method
method.setAccessible ( true );
return method;
}
}
}
}
// Search object superclass for this method
final Class superclass = currentClass.getSuperclass ();
if ( superclass != null )
{
return getMethodImpl ( topClass, superclass, methodName, types );
}
// Throwing proper method not found exception
throw new NoSuchMethodException ( "Method was not found: " +
topClass.getCanonicalName () + "." + methodName + argumentTypesToString ( types ) );
}
/**
* Returns text representation for array of argument types.
*
* @param types argument types array
* @return text representation for array of argument types
*/
@NotNull
private static String argumentTypesToString ( @Nullable final Class[] types )
{
final StringBuilder buf = new StringBuilder ( "(" );
if ( types != null )
{
for ( int i = 0; i < types.length; i++ )
{
if ( i > 0 )
{
buf.append ( ", " );
}
final Class c = types[ i ];
buf.append ( c == null ? "null" : c.getCanonicalName () );
}
}
return buf.append ( ")" ).toString ();
}
/**
* Returns cloned object.
*
* @param object object to clone
* @param cloned object type
* @return cloned object
* @throws NoSuchMethodException if method was not found
* @throws InvocationTargetException if method throws an exception
* @throws IllegalAccessException if method is inaccessible
*/
@Nullable
public static T clone ( @Nullable final T object )
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
return object != null ? ( T ) ReflectUtils.callMethod ( object, "clone" ) : null;
}
/**
* Returns cloned object.
*
* @param object object to clone
* @param cloned object type
* @return cloned object
*/
@Nullable
public static T cloneSafely ( @Nullable final T object )
{
return object != null ? ( T ) ReflectUtils.callMethodSafely ( object, "clone" ) : null;
}
/**
* Returns class loaded for the specified canonical class name.
*
* @param canonicalClassName canonical class name
* @return class loaded for the specified canonical class name
* @throws ClassNotFoundException if class was not found
*/
@NotNull
public static Class loadClass ( @NotNull final String canonicalClassName ) throws ClassNotFoundException
{
return ReflectUtils.class.getClassLoader ().loadClass ( canonicalClassName );
}
/**
* Returns an array of argument class types.
*
* @param arguments arguments to process
* @return an array of argument class types
*/
@NotNull
public static Class[] getClassTypes ( @NotNull final Object[] arguments )
{
final Class[] parameterTypes = new Class[ arguments.length ];
for ( int i = 0; i < arguments.length; i++ )
{
parameterTypes[ i ] = arguments[ i ] != null ? arguments[ i ].getClass () : null;
}
return parameterTypes;
}
/**
* Returns whether specified {@link Class} type is assignable from another one or not.
*
* @param type {@link Class} type to check against
* @param another {@link Class} to check check
* @return {@code true} if specified {@link Class} type is assignable from another one, {@code false} otherwise
*/
@SuppressWarnings ( "ConstantConditions" )
public static boolean isAssignable ( @NotNull final Class type, @Nullable final Class another )
{
boolean assignable = false;
if ( another == null )
{
assignable = !type.isPrimitive ();
}
else if ( type.isAssignableFrom ( another ) )
{
assignable = true;
}
else if ( type.isPrimitive () )
{
if ( type == boolean.class )
{
assignable = Boolean.class.isAssignableFrom ( another );
}
else if ( type == int.class )
{
assignable = Integer.class.isAssignableFrom ( another );
}
else if ( type == char.class )
{
assignable = Character.class.isAssignableFrom ( another );
}
else if ( type == byte.class )
{
assignable = Byte.class.isAssignableFrom ( another );
}
else if ( type == short.class )
{
assignable = Short.class.isAssignableFrom ( another );
}
else if ( type == long.class )
{
assignable = Long.class.isAssignableFrom ( another );
}
else if ( type == float.class )
{
assignable = Float.class.isAssignableFrom ( another );
}
else if ( type == double.class )
{
assignable = Double.class.isAssignableFrom ( another );
}
else if ( type == void.class )
{
assignable = Void.class.isAssignableFrom ( another );
}
}
return assignable;
}
/**
* Returns whether or not specified object has primitive type.
* Specified {@code object} must never be {@code null}.
*
* @param object object to check
* @return {@code true} if specified object has primitive type, {@code false} otherwise
*/
public static boolean isPrimitive ( @NotNull final Object object )
{
return isPrimitive ( object.getClass () );
}
/**
* Returns whether or not specified class type is primitive.
* Specified {@code clazz} must never be {@code null}.
*
* @param type class type to check
* @return {@code true} if specified class type is primitive, {@code false} otherwise
*/
@SuppressWarnings ( "ConstantConditions" )
public static boolean isPrimitive ( @NotNull final Class> type )
{
return type.isPrimitive () ||
Boolean.class.isAssignableFrom ( type ) ||
Character.class.isAssignableFrom ( type ) ||
Byte.class.isAssignableFrom ( type ) ||
Short.class.isAssignableFrom ( type ) ||
Integer.class.isAssignableFrom ( type ) ||
Long.class.isAssignableFrom ( type ) ||
Float.class.isAssignableFrom ( type ) ||
Double.class.isAssignableFrom ( type ) ||
Void.class.isAssignableFrom ( type );
}
/**
* Returns default primitive type value.
*
* @param type primitive class type
* @return default primitive type value
*/
@NotNull
public static Object getDefaultPrimitiveValue ( @NotNull final Class> type )
{
final Object value;
if ( type.isPrimitive () )
{
if ( type == boolean.class )
{
value = false;
}
else if ( type == int.class )
{
value = 0;
}
else if ( type == char.class )
{
value = '\u0000';
}
else if ( type == byte.class )
{
value = ( byte ) 0;
}
else if ( type == short.class )
{
value = ( short ) 0;
}
else if ( type == long.class )
{
value = 0L;
}
else if ( type == float.class )
{
value = 0.0f;
}
else if ( type == double.class )
{
value = 0.0d;
}
else
{
throw new IllegalArgumentException ( "Unknown primitive type: " + type );
}
}
else
{
throw new IllegalArgumentException ( "Type is not primitive: " + type );
}
return value;
}
/**
* Returns whether {@link Class} or one of it's superclasses contains specified text in their name or not.
*
* @param theClass {@link Class} to check
* @param text text to look for
* @return {@code true} if {@link Class} or one of it's superclasses contains specified text in their name, {@code false} otherwise
*/
public static boolean containsInClassOrSuperclassName ( @Nullable final Class theClass, @NotNull final String text )
{
boolean contains = false;
if ( theClass != null )
{
final String name = theClass.getCanonicalName ();
if ( name != null )
{
contains = name.contains ( text ) || containsInClassOrSuperclassName ( theClass.getSuperclass (), text );
}
else
{
contains = containsInClassOrSuperclassName ( theClass.getSuperclass (), text );
}
}
return contains;
}
/**
* Returns closest superclass for both of the specified classes.
*
* @param object1 first object to retrieve {@link Class} of
* @param object2 second object to retrieve {@link Class} of
* @return closest superclass for both of the specified classes
*/
@NotNull
public static Class getClosestSuperclass ( @NotNull final Object object1, @NotNull final Object object2 )
{
return getClosestSuperclass ( object1.getClass (), object2.getClass () );
}
/**
* Returns closest super {@link Class} for both of the specified {@link Class}es.
*
* @param class1 first {@link Class}
* @param class2 second {@link Class}
* @return closest super {@link Class} for both of the specified {@link Class}es
*/
@NotNull
public static Class getClosestSuperclass ( @NotNull final Class class1, @NotNull final Class class2 )
{
final Class closestSuperClass;
if ( class1.isAssignableFrom ( class2 ) )
{
closestSuperClass = class1;
}
else if ( class2.isAssignableFrom ( class1 ) )
{
closestSuperClass = class2;
}
else
{
final Class super1 = class1.getSuperclass ();
final Class super2 = class2.getSuperclass ();
closestSuperClass = getClosestSuperclass ( super1, super2 );
}
return closestSuperClass;
}
/**
* Adds {@link List} of specified {@link URL}s into {@link ClassLoader}'s class path.
*
* @param classLoader {@link ClassLoader} to modify class path for
* @param classPath {@link List} of {@link URL}s to add into {@link ClassLoader}'s class path
*/
public static void addToClasspath ( @NotNull final ClassLoader classLoader, @NotNull final List classPath )
{
if ( classLoader instanceof URLClassLoader )
{
try
{
// Workaround for class path modification via URLClassLoader
for ( final URL url : classPath )
{
ReflectUtils.callMethod ( classLoader, "addURL", url );
}
}
catch ( final Exception e )
{
throw new ReflectionException ( String.format (
"Unable to add classpath URLs into class loader %s",
classLoader.getClass ().getCanonicalName ()
), e );
}
}
else if ( SystemUtils.isJava9orAbove () )
{
try
{
// Workaround for class path modification via BuiltinClassLoader
final Class> builtInClassLoaderClass = Class.forName ( JAVA9_BUILT_IN_CLASS_LOADER );
if ( builtInClassLoaderClass.isAssignableFrom ( classLoader.getClass () ) )
{
// jdk.internal.loader.URLClassPath
final Object urlClassPath = ReflectUtils.getFieldValue ( classLoader, "ucp" );
for ( final URL url : classPath )
{
ReflectUtils.callMethod ( urlClassPath, "addURL", url );
}
}
else
{
throw new ReflectionException ( String.format (
"Plugin loading is not supported for class loader: %s",
classLoader.getClass ().getCanonicalName ()
) );
}
}
catch ( final ClassNotFoundException e )
{
throw new ReflectionException ( String.format (
"Unable to find %s class",
JAVA9_BUILT_IN_CLASS_LOADER
), e );
}
catch ( final Exception e )
{
throw new ReflectionException ( String.format (
"Unable to add classpath URLs into class loader %s",
classLoader.getClass ().getCanonicalName ()
), e );
}
}
else
{
throw new ReflectionException ( String.format (
"Plugin loading is not supported for class loader: %s",
classLoader.getClass ().getCanonicalName ()
) );
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy