All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bbottema.javareflection.ClassUtils Maven / Gradle / Ivy

Go to download

Java Reflection provides a small package with nifty reflection features that will help with finding constructors, methods and value conversions

There is a newer version: 4.1.0
Show newest version
package org.bbottema.javareflection;

import lombok.experimental.UtilityClass;
import org.bbottema.javareflection.model.MethodModifier;
import org.bbottema.javareflection.util.ExternalClassLoader;
import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * Utility with convenience methods that operate on the class level.
 * 
    *
  • With this helper class you can locate and/or load classes. An advanced Class lookup ({@link #locateClass(String, boolean, * ClassLoader)}), that allows a full scan (to try all * packages known) and an optional {@link ExternalClassLoader} instance that is able to actually compile a .java file on the fly and load its compile * .class file
  • *
  • create a new instance while handling all the exceptions
  • *
  • find fields or assign values to fields, using casting, autoboxing or type conversions
  • *
  • simply give back a list of field / method names
  • *
*/ @UtilityClass public final class ClassUtils { /** * {@link Class} cache optionally used when looking up classes with {@link #locateClass(String, boolean, ClassLoader)}. */ private final static Map> classCache = new HashMap<>(); @SuppressWarnings("WeakerAccess") public static void resetCache() { classCache.clear(); } /** * Searches the JVM and optionally all of its packages * * @param className The name of the class to locate. * @param fullscan Whether a full scan through all available java packages is required. * @param classLoader Optional user-provided classloader. * @return The Class reference if found or null otherwise. */ @Nullable @SuppressWarnings("WeakerAccess") public static Class locateClass(final String className, final boolean fullscan, @Nullable final ClassLoader classLoader) { final String cacheKey = className + fullscan; if (classCache.containsKey(cacheKey)) { return classCache.get(cacheKey); } final Class _class; if (fullscan) { _class = locateClass(className, null, classLoader); } else { // try standard package used for most common classes _class = locateClass(className, "java.lang", classLoader); } classCache.put(cacheKey, _class); return _class; } @Nullable @SuppressWarnings("WeakerAccess") public static Class locateClass(final String className, @Nullable final String inPackage, @Nullable final ClassLoader classLoader) { final String cacheKey = className + inPackage; if (classCache.containsKey(cacheKey)) { return classCache.get(cacheKey); } Class _class = locateClass(className, classLoader); if (_class == null) { _class = PackageUtils.scanPackagesForClass(className, inPackage, classLoader); } classCache.put(cacheKey, _class); return _class; } /** * This function dynamically tries to locate a class. First it searches the class-cache list, then it tries to get it from the Virtual Machine * using {@code Class.forName(String)}. * * @param fullClassName The Class that needs to be found. * @param classLoader Optional user-provided classloader. * @return The {@code Class} object found from cache or VM. */ @SuppressWarnings("WeakerAccess") @Nullable public static Class locateClass(final String fullClassName, @Nullable final ClassLoader classLoader) { try { Class _class = null; if (classLoader != null) { _class = classLoader.loadClass(fullClassName); } if (_class == null) { _class = Class.forName(fullClassName); } return _class; } catch (final ClassNotFoundException e) { return null; } } /** * Simply calls {@link Class#newInstance()} and hides the exception handling boilerplate code. * * @param _class The datatype for which we need to create a new instance of. * @param Type used to parameterize the return instance. * @return A new parameterized instance of the given type. */ @NotNull @SuppressWarnings("WeakerAccess") public static T newInstanceSimple(final Class _class) { try { return _class.getConstructor().newInstance(); } catch (SecurityException e) { throw new RuntimeException("unable to invoke parameterless constructor; security problem", e); } catch (InstantiationException e) { throw new RuntimeException("unable to complete instantiation of object", e); } catch (IllegalAccessException e) { throw new RuntimeException("unable to access parameterless constructor", e); } catch (InvocationTargetException e) { throw new RuntimeException("unable to invoke parameterless constructor", e); } catch (NoSuchMethodException e) { throw new RuntimeException("unable to find parameterless constructor (not public?)", e); } } /** * Returns a field from the given object that goes by the name of fieldName. If o is a Class object, a static field will * be returned. * * @param o The reference to the object to fetch the property value from. * @param fieldName The identifier or name of the member field/property. * @return The value of the Field. */ @Nullable @SuppressWarnings("WeakerAccess") public static Field solveField(final Object o, final String fieldName) { try { if (o.getClass().equals(Class.class)) { // Java static field return ((Class) o).getField(fieldName); } else { // Java instance field return o.getClass().getField(fieldName); } } catch (NoSuchFieldException e) { return null; } } /** * Assigns a value to a field id on the given object o. If a simple assignment fails, a common conversion will be * attempted. * * @param o The object to find the field on. * @param property The name of the field we're assigning the value to. * @param value The value to assign to the field, may be converted to the field's type through common conversion. * @return The actual value that was assigned (the original or the converted value). * @throws IllegalAccessException Thrown by {@link Field#set(Object, Object)} * @throws NoSuchFieldException Thrown if the {@link Field} could not be found, even after trying to convert the value to the target type. * @see ValueConversionHelper#convert(Object, Class) */ @Nullable @SuppressWarnings("WeakerAccess") public static Object assignToField(final Object o, final String property, final Object value) throws IllegalAccessException, NoSuchFieldException { final Field field = solveField(o, property); if (field != null) { Object assignedValue = value; try { field.set(o, value); } catch (final IllegalArgumentException ie) { assignedValue = ValueConversionHelper.convert(value, field.getType()); field.set(o, assignedValue); } return assignedValue; } else { throw new NoSuchFieldException(); } } /** * Returns a list of names that represent the fields on an Object. * * @param subject The Object who's properties/fields need to be reflected. * @return A list of names that represent the fields on the given Object. */ @NotNull @SuppressWarnings("WeakerAccess") public static Collection collectPropertyNames(final Object subject) { final Collection properties = new LinkedHashSet<>(); final Field[] fields = subject.getClass().getFields(); for (final Field f : fields) { properties.add(f.getName()); } return properties; } /** * @return Returns the result of {@link #collectMethods(Class, Class, EnumSet)} mapped to the method names. */ @SuppressWarnings("WeakerAccess") public static Set collectMethodNames(Class dataType, Class boundaryMarker, EnumSet methodModifiers) { Set methodNames = new HashSet<>(); for (Method m : collectMethods(dataType, boundaryMarker, methodModifiers)) { methodNames.add(m.getName()); } return methodNames; } /** * @return The result of {@link #collectMethodsMappingToName(Class, Class, EnumSet)} filtered on method name. */ @SuppressWarnings("WeakerAccess") public static Set collectMethodsByName(final Class type, Class boundaryMarker, EnumSet methodModifiers, final String methodName) { return collectMethodsMappingToName(type, boundaryMarker, methodModifiers).get(methodName); } /** * @return The result of {@link #collectMethods(Class, Class, EnumSet)} filtered on method name. */ @SuppressWarnings("WeakerAccess") public static Map> collectMethodsMappingToName(Class type, Class boundaryMarker, EnumSet methodModifiers) { Map> methodsMappedToName = new HashMap<>(); for (Method method : collectMethods(type, boundaryMarker, methodModifiers)) { if (!methodsMappedToName.containsKey(method.getName())) { methodsMappedToName.put(method.getName(), new HashSet()); } methodsMappedToName.get(method.getName()).add(method); } return methodsMappedToName; } /** * Returns a list of names that represent the methods on an Object * * @param methodModifiers List of method modifiers that will match any method that has one of them. * @param boundaryMarker Optional type to limit (including) how far back up the inheritance chain we go for discovering methods. * @return Returns a list with methods, either {@link Method}s. */ @SuppressWarnings("WeakerAccess") public static Set collectMethods(Class dataType, Class boundaryMarker, EnumSet methodModifiers) { final Set allMethods = new HashSet<>(); for (Method declaredMethod : dataType.getDeclaredMethods()) { if (MethodModifier.meetsModifierRequirements(declaredMethod, methodModifiers)) { allMethods.add(declaredMethod); } } if (dataType != boundaryMarker && dataType.getSuperclass() != null) { allMethods.addAll(collectMethods(dataType.getSuperclass(), boundaryMarker, methodModifiers)); } return allMethods; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy