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

refutils.FieldHelper Maven / Gradle / Ivy

package refutils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Contains utility methods to get and set field value from an instance of a class. The field can be located by class
 * type or field name.
 */
class FieldHelper {
    private final Object instance;
    private final Collection allFields;

    /**
     * Instantiates a FieldHelper.
     *
     * @param instance the instance where the fields are located
     */
    FieldHelper(Object instance) {
        this.instance = instance;
        this.allFields = new FieldExtractor(instance.getClass()).getAllFields();
    }

    /**
     * Get the value for the named field
     *
     * @param fieldName the name of the field
     * @return the field value
     * @throws IllegalAccessException if the underlying field is inaccessible.
     * @throws NoSuchFieldException   thrown if field cannot be located
     */
    Object getValue(String fieldName) throws IllegalAccessException, NoSuchFieldException {
        Field field = getFieldByName(fieldName);
        MakeFieldAccessible makeFieldAccessible = new MakeFieldAccessible(field);

        Object returnValue = field.get(instance);

        makeFieldAccessible.restoreAccessState();

        return returnValue;
    }

    /**
     * Get the value for the matching field by looking at class type.
     *
     * @return the field value
     * @throws IllegalAccessException if the underlying field is inaccessible.
     * @throws NoSuchFieldException   thrown if field cannot be located
     */
    @SuppressWarnings("unchecked")
     T getValue(Class valueClass) throws IllegalAccessException, NoSuchFieldException {
        checkForObjectValueClass(valueClass);

        Field field = getFieldByType(valueClass);
        MakeFieldAccessible makeFieldAccessible = new MakeFieldAccessible(field);

        Object returnValue = field.get(instance);

        makeFieldAccessible.restoreAccessState();

        return (T) returnValue;
    }

    /**
     * Inserts a value for the named field
     *
     * @param fieldName the name of the field
     * @param value     the field value to set
     * @throws IllegalAccessException if the underlying field is inaccessible.
     * @throws NoSuchFieldException   thrown if field cannot be located
     */
    void setValue(String fieldName, Object value) throws IllegalAccessException, NoSuchFieldException {
        Field field = getFieldByName(fieldName);
        MakeFieldAccessible makeFieldAccessible = new MakeFieldAccessible(field);

        field.set(instance, value);

        makeFieldAccessible.restoreAccessState();
    }

    /**
     * Inserts a value for the matching field by looking at the value class type.
     *
     * @param value the field value to set
     * @throws IllegalAccessException if the underlying field is inaccessible.
     * @throws NoSuchFieldException   thrown if field cannot be located
     */
    void setValue(Object value) throws IllegalAccessException, NoSuchFieldException {
        checkForObjectValueClass(value.getClass());

        Field field = getFieldByType(value.getClass());
        MakeFieldAccessible makeFieldAccessible = new MakeFieldAccessible(field);

        field.set(instance, value);

        makeFieldAccessible.restoreAccessState();
    }

    private Field getFieldByName(String fieldName) throws NoSuchFieldException {
        for (Field potentialField : allFields) {
            if (potentialField.getName().equals(fieldName)) {
                return potentialField;
            }
        }
        throw new NoSuchFieldException(String.format("Cannot find visible field named %s", fieldName));
    }

    private void checkForObjectValueClass(Class valueClass) {
        if (valueClass == Object.class) {
            throw new IllegalArgumentException("Cannot match Object.class type parameter, you must specify it by name");
        }
    }

    private Field getFieldByType(Class valueClass) throws NoSuchFieldException {
        Collection matchingFields = allFields;

        matchingFields = filterOnTypeMatches(matchingFields, valueClass);
        if (matchingFields.size() == 0) {
            throw new NoSuchFieldException(String.format("Cannot find visible field for %s", valueClass));
        }
        if (matchingFields.size() > 1) {
            throw new IllegalArgumentException(String.format("Found too many (%s) matches for field %s %s, specify the field by name instead", matchingFields.size(),
                    valueClass, extractFieldNames(matchingFields)));
        }

        return matchingFields.iterator().next();
    }

    private Collection filterOnTypeMatches(Collection matchingFields, Class valueClass) {
        List returnValue = new ArrayList();
        PrimitiveMatcher primitiveMatcher = new PrimitiveMatcher(valueClass);

        for (Field matchingField : matchingFields) {
            if (matchingField.getType() != Object.class && (primitiveMatcher.isMatchedPrimitive(matchingField.getType()) || matchingField.getType().isAssignableFrom(valueClass))) {
                returnValue.add(matchingField);
            }
        }
        return returnValue;
    }

    private String extractFieldNames(Collection matchingFields) {
        List fieldNames = new ArrayList();
        for (Field matchingField : matchingFields) {
            fieldNames.add(matchingField.getName());
        }
        return fieldNames.toString();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy