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

de.alpharogroup.reflection.ReflectionExtensions Maven / Gradle / Ivy

The newest version!
/**
 * The MIT License
 *
 * Copyright (C) 2015 Asterios Raptis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package de.alpharogroup.reflection;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.stream.Collectors;

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;

import de.alpharogroup.lang.ClassExtensions;
import de.alpharogroup.lang.ClassType;
import lombok.NonNull;
import lombok.experimental.UtilityClass;
import lombok.extern.java.Log;

/**
 * The class {@link ReflectionExtensions} provides utility methods for the java reflection API
 */
@UtilityClass
@Log
public final class ReflectionExtensions
{

	/**
	 * Creates a new array instance from the same type as the given {@link Class} and the given
	 * length
	 *
	 * @param 
	 *            the generic type
	 * @param cls
	 *            the class object
	 * @param length
	 *            the length of the array
	 * @return the new array instance
	 */
	@SuppressWarnings("unchecked")
	public static  T[] newArrayInstance(final @NonNull Class cls, final int length)
	{
		return (T[])Array.newInstance(cls, length);
	}

	/**
	 * Creates a new empty array instance from the given source array the length of the given source
	 * array
	 *
	 * @param 
	 *            the generic type
	 * @param source
	 *            the source array
	 * @return the new empty array instance
	 */
	@SuppressWarnings("unchecked")
	public static  T[] newEmptyArrayInstance(final @NonNull T[] source)
	{
		return (T[])newArrayInstance(source.getClass().getComponentType(), source.length);
	}

	/**
	 * Copy the given array object and return a copy of it.
	 *
	 * @param 
	 *            the generic type
	 * @param source
	 *            the source
	 * @return the copy of the given array object
	 */
	public static  T[] copyArray(final @NonNull T[] source)
	{
		T[] destination = newEmptyArrayInstance(source);
		for (int i = 0; i < Array.getLength(source); i++)
		{
			Array.set(destination, i, Array.get(source, i));
		}
		return destination;
	}

	/**
	 * Copies the field value of the given source object to the given target object.
	 *
	 * @param 
	 *            the generic type of the object
	 * @param source
	 *            the source
	 * @param target
	 *            the target
	 * @param fieldName
	 *            the field name
	 * @throws NoSuchFieldException
	 *             is thrown if no such field exists.
	 * @throws SecurityException
	 *             is thrown if a security manager says no.
	 * @throws IllegalAccessException
	 *             is thrown if an illegal on create an instance or access a method.
	 */
	public static  void copyFieldValue(final @NonNull T source, final @NonNull T target,
		final @NonNull String fieldName)
		throws NoSuchFieldException, SecurityException, IllegalAccessException
	{
		setFieldValue(source, target, getDeclaredField(source, fieldName));
	}

	/**
	 * Sets the field value of the given source object over the field
	 *
	 * @param 
	 *            the generic type
	 * @param source
	 *            the source object
	 * @param target
	 *            the target
	 * @param sourceField
	 *            the source field
	 * @throws IllegalAccessException
	 *             is thrown if an illegal on create an instance or access a method
	 * @throws SecurityException
	 *             is thrown if a security manager says no
	 */
	public static  void setFieldValue(final @NonNull T source, final @NonNull T target,
		final @NonNull Field sourceField) throws IllegalAccessException
	{
		sourceField.setAccessible(true);
		final Object sourceValue = sourceField.get(source);
		setFieldValue(target, sourceField, sourceValue);
	}

	/**
	 * Sets the field value of the given source object
	 *
	 * @param 
	 *            the generic type
	 * @param source
	 *            the source object
	 * @param field
	 *            the field
	 * @param newValue
	 *            the new value
	 * @throws IllegalAccessException
	 *             is thrown if an illegal on create an instance or access a method
	 */
	public static  void setFieldValue(final T source, final Field field, final Object newValue)
		throws IllegalAccessException
	{
		field.setAccessible(true);
		field.set(source, newValue);
	}

	/**
	 * Gets the field value of the given source object over the field name.
	 *
	 * @param 
	 *            the generic type
	 * @param source
	 *            the source
	 * @param fieldName
	 *            the field name
	 * @return the field value
	 * @throws NoSuchFieldException
	 *             is thrown if no such field exists.
	 * @throws SecurityException
	 *             is thrown if a security manager says no.
	 * @throws IllegalAccessException
	 *             is thrown if an illegal on create an instance or access a method.
	 */
	public static  Object getFieldValue(final @NonNull T source, final @NonNull String fieldName)
		throws NoSuchFieldException, SecurityException, IllegalAccessException
	{
		final Field sourceField = getDeclaredField(source, fieldName);
		sourceField.setAccessible(true);
		return sourceField.get(source);
	}

	/**
	 * Sets the field value of the given class object over the field name.
	 *
	 * @param 
	 *            the generic type
	 * @param cls
	 *            The class
	 * @param fieldName
	 *            the field name
	 * @param newValue
	 *            the new value
	 * @throws NoSuchFieldException
	 *             is thrown if no such field exists.
	 * @throws SecurityException
	 *             is thrown if a security manager says no.
	 * @throws IllegalAccessException
	 *             is thrown if an illegal on create an instance or access a method.
	 */
	public static  void setFieldValue(final @NonNull Class cls,
		final @NonNull String fieldName, final Object newValue)
		throws NoSuchFieldException, SecurityException, IllegalAccessException
	{
		final Field sourceField = getDeclaredField(cls, fieldName);
		sourceField.setAccessible(true);
		sourceField.set(null, newValue);
	}

	/**
	 * Gets all field names from the given class as an String list.
	 *
	 * @param cls
	 *            The class object to get the field names.
	 *
	 * @return Gets all field names from the given class as an String list.
	 */
	public static List getFieldNames(final @NonNull Class cls)
	{
		return Arrays.stream(cls.getDeclaredFields()).filter(ReflectionExtensions::isNotSynthetic)
			.map(Field::getName).collect(Collectors.toList());
	}

	/**
	 * Gets all field names from the given class as an String list minus the given ignored field
	 * names
	 *
	 * @param cls
	 *            The class object to get the field names
	 * @param ignoreFieldNames
	 *            a list with field names that shell be ignored
	 *
	 * @return Gets all field names from the given class as an String list minus the given ignored
	 *         field names
	 */
	public static List getFieldNames(final @NonNull Class cls,
		List ignoreFieldNames)
	{
		return Arrays.stream(cls.getDeclaredFields()).filter(ReflectionExtensions::isNotSynthetic)
			.map(Field::getName).filter(name -> !ignoreFieldNames.contains(name))
			.collect(Collectors.toList());
	}

	/**
	 * Gets all field names from the given class as an String list minus the given optional array of
	 * ignored field names
	 *
	 * @param cls
	 *            The class object to get the field names
	 * @param ignoreFieldNames
	 *            a optional array with the field names that shell be ignored
	 *
	 * @return Gets all field names from the given class as an String list minus the given optional
	 *         array of ignored field names
	 */
	public static List getFieldNames(final @NonNull Class cls,
		String... ignoreFieldNames)
	{
		return getFieldNames(cls, Arrays.asList(ignoreFieldNames));
	}

	/**
	 * Gets all the declared field names from the given class object.
	 *
	 * Note: without the field names from any superclasses
	 *
	 * @param cls
	 *            the class object
	 * @return all the declared field names from the given class as an String array
	 */
	public static String[] getDeclaredFieldNames(final @NonNull Class cls)
	{
		return Arrays.stream(cls.getDeclaredFields()).filter(ReflectionExtensions::isNotSynthetic)
			.map(Field::getName).toArray(String[]::new);
	}

	/**
	 * Gets all the declared field names from the given class object minus the given ignored field
	 * names
	 *
	 * Note: without the field names from any superclasses
	 *
	 * @param cls
	 *            the class object
	 * @param ignoreFieldNames
	 *            a optional array with the field names that shell be ignored
	 * @return all the declared field names from the given class as an String array minus the given
	 *         optional array of ignored field names
	 */
	public static String[] getDeclaredFieldNames(final @NonNull Class cls,
		String... ignoreFieldNames)
	{
		return getDeclaredFieldNames(cls, Arrays.asList(ignoreFieldNames));
	}

	/**
	 * Gets all the declared field names from the given class object minus the given ignored field
	 * names
	 *
	 * Note: without the field names from any superclasses
	 *
	 * @param cls
	 *            the class object
	 * @param ignoreFieldNames
	 *            a list with field names that shell be ignored
	 * @return all the declared field names from the given class as an String array minus the given
	 *         ignored field names
	 */
	public static String[] getDeclaredFieldNames(final @NonNull Class cls,
		List ignoreFieldNames)
	{
		return Arrays.stream(cls.getDeclaredFields()).filter(ReflectionExtensions::isNotSynthetic)
			.map(Field::getName).filter(name -> !ignoreFieldNames.contains(name))
			.toArray(String[]::new);
	}

	/**
	 * Checks if the given {@link Field} is not synthetic
	 *
	 * @param field
	 *            the field
	 * @return true, if the given {@link Field} is not synthetic otherwise false
	 */
	public static boolean isNotSynthetic(@NonNull Field field)
	{
		return !field.isSynthetic();
	}

	/**
	 * Gets all method names from the given class as an String array.
	 *
	 * @param cls
	 *            The class object to get the method names.
	 *
	 * @return Gets all method names from the given class as an String array.
	 */
	public static String[] getMethodNames(final @NonNull Class cls)
	{
		final Method[] methods = cls.getDeclaredMethods();
		final String[] methodNames = new String[methods.length];
		for (int i = 0; i < methods.length; i++)
		{
			methodNames[i] = methods[i].getName();
		}
		return methodNames;
	}

	/**
	 * Generates a Map with the fieldName as key and the method as value. Concatenates the given
	 * prefix and the field name and puts the result into the map.
	 *
	 * @param fieldNames
	 *            A list with the field names.
	 * @param prefix
	 *            The prefix for the method name.
	 *
	 * @return the method names with prefix from field names
	 */
	public static Map getMethodNamesWithPrefixFromFieldNames(
		final @NonNull List fieldNames, final String prefix)
	{
		final Map fieldNameMethodMapper = new HashMap<>();
		for (final String fieldName : fieldNames)
		{
			final String firstCharacterToUpperCasefieldName = firstCharacterToUpperCase(fieldName);
			final String methodName = prefix + firstCharacterToUpperCasefieldName;
			fieldNameMethodMapper.put(fieldName, methodName);
		}
		return fieldNameMethodMapper;
	}

	/**
	 * Sets the first character from the given string to upper case and returns it. Example:
* Given fieldName: userName
* Result: UserName * * @param fieldName * The String to modify. * @return The modified string. */ public static String firstCharacterToUpperCase(final @NonNull String fieldName) { String firstCharacter = fieldName.substring(0, 1); firstCharacter = firstCharacter.toUpperCase(); final char[] fc = firstCharacter.toCharArray(); final char[] fn = fieldName.toCharArray(); fn[0] = fc[0]; return new String(fn); } /** * Gets the modifiers from the given Field as a list of String objects. * * @param field * The field to get the modifiers. * @return A list with the modifiers as String objects from the given Field. */ public static List getModifiers(final @NonNull Field field) { final String modifiers = Modifier.toString(field.getModifiers()); final String[] modifiersArray = modifiers.split(" "); return Arrays.asList(modifiersArray); } /** * Creates a new instance from the same type as the given object. * * @param * the generic type * @param object * the object * @return the new instance */ @SuppressWarnings("unchecked") public static T newInstance(final @NonNull T object) { Class clazz = object.getClass(); ClassType classType = ClassExtensions.getClassType(clazz); switch (classType) { case ARRAY : int length = Array.getLength(object); return (T)Array.newInstance(clazz.getComponentType(), length); default : return newInstance((Class)object.getClass()); } } /** * Factory method for create a new instance from the same type as the given {@link Class}. First * try is over the class and second try is with objenesis.
*
* Note: if non of the tries no instance could created null will be returned. * * @param * the generic type * @param clazz * the Class object * @return the new instance */ public static T newInstance(final @NonNull Class clazz) { T newInstance = null; Optional optionalNewInstance; optionalNewInstance = forceNewInstanceWithClass(clazz); if (optionalNewInstance.isPresent()) { return optionalNewInstance.get(); } optionalNewInstance = forceNewInstanceWithObjenesis(clazz); if (optionalNewInstance.isPresent()) { return optionalNewInstance.get(); } return newInstance; } private static Optional forceNewInstanceWithClass(final @NonNull Class clazz) { Optional optionalNewInstance = Optional.empty(); try { optionalNewInstance = Optional.of(newInstanceWithClass(clazz)); } catch (InstantiationException | IllegalAccessException e) { log.log(Level.INFO, "Failed to create new instance with method Class.newInstance()", e); } return optionalNewInstance; } private static Optional forceNewInstanceWithObjenesis(final @NonNull Class clazz) { Optional optionalNewInstance = Optional.empty(); try { optionalNewInstance = Optional.of(newInstanceWithObjenesis(clazz)); } catch (Exception e) { log.log(Level.INFO, "Failed to create new instance with Objenesis ObjectInstantiator.newInstance()", e); } return optionalNewInstance; } /** * Creates a new instance from the same type as the given {@link Class} * * @param * the generic type * @param clazz * the Class object * @return the new instance * @throws IllegalAccessException * is thrown if the class or its default constructor is not accessible. * @throws InstantiationException * is thrown if this {@code Class} represents an abstract class, an interface, an * array class, a primitive type, or void; or if the class has no default * constructor; or if the instantiation fails for some other reason. */ public static T newInstanceWithClass(final @NonNull Class clazz) throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } /** * Creates a new instance from the same type as the given {@link Class} * * @param * the generic type * @param clazz * the Class object * @return the new instance */ public static T newInstanceWithObjenesis(final @NonNull Class clazz) { Objenesis objenesis = new ObjenesisStd(); ObjectInstantiator instantiator = objenesis.getInstantiatorOf(clazz); return instantiator.newInstance(); } /** * Gets the {@link Field} that match to the given field name that exists in the given object. * * @param * the generic type * @param object * the object * @param fieldName * the field name * @return the declared field * @throws NoSuchFieldException * is thrown if no such field exists. * @throws SecurityException * is thrown if a security manager says no. */ public static Field getDeclaredField(@NonNull final T object, final @NonNull String fieldName) throws NoSuchFieldException, SecurityException { return getDeclaredField(object.getClass(), fieldName); } /** * Gets the {@link Field} that match to the given field name that exists in the given class. * * @param cls * the class object * @param fieldName * the field name * @return the declared field * @throws NoSuchFieldException * is thrown if no such field exists. * @throws SecurityException * is thrown if a security manager says no. */ public static Field getDeclaredField(final @NonNull Class cls, final @NonNull String fieldName) throws NoSuchFieldException, SecurityException { return cls.getDeclaredField(fieldName); } /** * Gets all the declared fields including all fields from all super classes from the given class * object minus the given ignored fields * * @param cls * the class object * @param ignoreFieldNames * an optional array with field names that shell be ignored * @return all the declared fields minus the given ignored field names */ public static Field[] getAllDeclaredFields(final @NonNull Class cls, final String... ignoreFieldNames) { return getAllDeclaredFields(cls, Arrays.asList(ignoreFieldNames)); } /** * Gets all the declared fields including all fields from all super classes from the given class * object minus the given ignored fields * * @param cls * the class object * @param ignoreFieldNames * a list with field names that shell be ignored * @return all the declared fields minus the given ignored field names */ public static Field[] getAllDeclaredFields(final @NonNull Class cls, List ignoreFieldNames) { Field[] declaredFields = getDeclaredFields(cls, ignoreFieldNames); Class superClass = cls.getSuperclass(); if (superClass != null && superClass.equals(Object.class)) { return declaredFields; } List fields = new ArrayList<>(Arrays.asList(declaredFields)); while ((superClass != null && superClass.getSuperclass() != null && superClass.getSuperclass().equals(Object.class))) { fields.addAll(Arrays.asList(getDeclaredFields(superClass, ignoreFieldNames))); superClass = superClass.getSuperclass(); } return fields.toArray(new Field[] { }); } /** * Gets all the declared field names including all fields from all super classes from the given * class object * * @param cls * the class object * @return all the declared field names */ public static String[] getAllDeclaredFieldNames(final @NonNull Class cls) { return Arrays.stream(getAllDeclaredFields(cls)).map(Field::getName).toArray(String[]::new); } /** * Gets all the declared field names including all fields from all super classes from the given * class object minus the given optional array of ignored field names * * @param cls * the class object * @param ignoreFieldNames * an optional array with the field names that shell be ignored * @return all the declared field names minus the given optional array of ignored field names */ public static String[] getAllDeclaredFieldNames(final @NonNull Class cls, String... ignoreFieldNames) { return getAllDeclaredFieldNames(cls, Arrays.asList(ignoreFieldNames)); } /** * Gets all the declared field names including all fields from all super classes from the given * class object minus the given ignored field names * * @param cls * the class object * @param ignoreFieldNames * a list with field names that shell be ignored * @return all the declared field names minus the given ignored field names */ public static String[] getAllDeclaredFieldNames(final @NonNull Class cls, List ignoreFieldNames) { Field[] allDeclaredFields = getAllDeclaredFields(cls); return Arrays.stream(allDeclaredFields).map(Field::getName) .filter(name -> !ignoreFieldNames.contains(name)).toArray(String[]::new); } /** * Gets the declared fields from the given class minus the given ignored field names * * @param cls * the class object * @param ignoreFieldNames * a list with field names that shell be ignored * @return the declared {@link Field} from the given class minus the given ignored field names * @throws SecurityException * is thrown if a security manager says no */ public static Field[] getDeclaredFields(final @NonNull Class cls, List ignoreFieldNames) throws SecurityException { return Arrays.stream(cls.getDeclaredFields()) .filter(field -> !ignoreFieldNames.contains(field.getName())).toArray(Field[]::new); } /** * Gets the declared fields from the given class minus the given optional array of ignored field * names * * @param cls * the class object * @param ignoreFieldNames * a list with field names that shell be ignored * @return the declared {@link Field} from the given class minus the given optional array of * ignored field names * @throws SecurityException * is thrown if a security manager says no */ public static Field[] getDeclaredFields(final @NonNull Class cls, String... ignoreFieldNames) throws SecurityException { return getDeclaredFields(cls, Arrays.asList(ignoreFieldNames)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy