![JAR search and dependency download from the Maven repository](/logo.png)
org.bithill.selenium.resolving.Reflection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aport Show documentation
Show all versions of aport Show documentation
web UI testing made easier
package org.bithill.selenium.resolving;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
/**
* Collection of utility functions for reflection.
*/
class Reflection
{
/** Provides list of all fields this object has, including fields in ancestors.
* These fields are candidates for resolve.
*
* @param instance object for which we want to get the fields
* @param rootClass the root class of inheritance hierarchy, ancestors of this class are not searched for fields
* @return list of fields
*/
public static Field[] getClassFields(@Nonnull Object instance, @Nullable Class rootClass)
{
List fields = new ArrayList<>();
// 1. add all fields the class declares
fields.addAll(Arrays.asList(instance.getClass().getDeclaredFields()));
// 2. add all fields of ancestor classes, up to the Resolvable (including)
Class currentlyProcessedClass = instance.getClass();
Class superClass;
while ( (superClass = currentlyProcessedClass.getSuperclass()) != null )
{
if (superClass != rootClass)
{
fields.addAll(Arrays.asList(superClass.getDeclaredFields()));
currentlyProcessedClass = superClass;
}
else
{
break;
}
}
return fields.toArray(new Field[fields.size()]);
}
/** Provides list of all fields this object has, including fields in ancestors.
* These fields are candidates for resolve.
*
* @param instance object for which we want to get the fields
* @return list of fields
*/
public static Field[] getClassFields(@Nonnull Object instance)
{
return getClassFields(instance, Object.class);
}
/** Gets value of the field, regardless of its access modifiers.
*
* @param instance object from which we want to get the field
* @param field the field we want got get value of
*
* @return value of the field
*/
public static Object getFieldValue(@Nonnull Object instance, @Nonnull Field field)
{
Object result;
field.setAccessible(true);
try
{
result = field.get(instance);
}
catch (IllegalAccessException ex)
{
throw new RuntimeException(ex);
}
field.setAccessible(false);
return result;
}
/** Sets given field if it matches provided predicate.
*
* @param instance object for which we want to set the field
* @param field the field to check and set
* @param value the value to which we want the field to be set
* @param fieldPredicate predicate the field must match (fieldPredicate.test() returns true) to be set
*/
public static void setFieldValue(@Nonnull Object instance, @Nonnull Field field, Object value, Predicate fieldPredicate)
{
try
{
field.setAccessible(true);
if ( fieldPredicate.test(field)) { field.set(instance, value); }
field.setAccessible(false);
}
catch (IllegalAccessException ex)
{
throw new RuntimeException(String.format("Field %s cannot be set.", field.getName()), ex);
}
}
/** Sets given field.
*
* @param instance object for which we want to set the field
* @param field the field to check and set
* @param value the value to which we want the field to be set
*/
public static void setFieldValue(@Nonnull Object instance, @Nonnull Field field, Object value)
{
setFieldValue(instance, field, value, aField -> true);
}
/** Check if the field is of desired type and has null value, if so, creates a new instance using default
* constructor ans sets it to the field. Already set fields are not modified.
*
* @param instance object for which we want to set the field
* @param field the field to check and set
*
* @return new instance of the field class for null-value field, existing value for non-null field
*
* @throws IllegalAccessException
*/
public static Object createAndSetField(@Nonnull Object instance, @Nonnull Field field, Set allowedClasses)
throws IllegalAccessException
{
Object fieldValue = getFieldValue(instance, field);
Class fieldType = field.getType();
// flag if the field type is allowed class or inherits from an allowed class
@SuppressWarnings("unchecked")
boolean isAllowedClass = allowedClasses.stream().anyMatch(aClass -> aClass.isAssignableFrom(fieldType));
if (isAllowedClass && fieldValue == null)
{
try
{
setFieldValue(instance, field, fieldType.newInstance());
fieldValue = getFieldValue(instance, field);
}
catch (InstantiationException ex)
{
throw new RuntimeException(ex);
}
}
return fieldValue;
}
/** Retrieves type arguments of a given field.
*
* @param field of {@link ParameterizedType}
* @return type arguments for a field of parametrized type, empty array for a filed of non-parametrized type
*/
public static Type[] getFieldTypeArguments(@Nonnull Field field)
{
Type[] result = new Type[0];
Type genericFieldType = field.getGenericType();
if (genericFieldType instanceof ParameterizedType)
{
ParameterizedType aType = (ParameterizedType) genericFieldType;
return aType.getActualTypeArguments();
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy