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

io.microsphere.reflect.FieldUtils Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.microsphere.reflect;

import io.microsphere.logging.Logger;
import io.microsphere.util.BaseUtils;

import java.lang.reflect.Field;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;

import static io.microsphere.lang.function.Predicates.and;
import static io.microsphere.lang.function.Streams.filter;
import static io.microsphere.lang.function.ThrowableSupplier.execute;
import static io.microsphere.logging.LoggerFactory.getLogger;
import static io.microsphere.reflect.AccessibleObjectUtils.trySetAccessible;
import static io.microsphere.text.FormatUtils.format;
import static io.microsphere.util.ClassUtils.getAllInheritedTypes;
import static java.util.Arrays.asList;

/**
 * The Java Reflection {@link Field} Utility class
 *
 * @author Mercy
 * @since 1.0.0
 */
public abstract class FieldUtils extends BaseUtils {

    private static final Logger logger = getLogger(FieldUtils.class);

    /**
     * Find the specified objects' declared {@link Field} by its' name
     *
     * @param object    the {@link Object object} to find
     * @param fieldName the name of {@link Field field}
     * @return null if not found
     */
    public static Field findField(Object object, String fieldName) {
        return findField(object.getClass(), fieldName);
    }

    /**
     * Find the declared {@link Field} by its' name
     *
     * @param klass     {@link Class class} to find
     * @param fieldName the name of {@link Field field}
     * @return null if not found
     */
    public static Field findField(Class klass, String fieldName) {
        if (klass == null || Object.class.equals(klass)) {
            return null;
        }
        Field field = null;
        try {
            field = klass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            // ignore, try the super class
            field = findField(klass.getSuperclass(), fieldName);
        }
        if (field == null) {
            if (logger.isTraceEnabled()) {
                logger.trace("The field[name :'{}'] not found in class : '{}'", fieldName, klass);
            }
        }
        return field;
    }

    /**
     * Find the declared {@link Field} by its' name
     *
     * @param klass     {@link Class class} to find
     * @param fieldName the name of {@link Field field}
     * @param fieldType the {@link Class type} of {@link Field field}
     * @return null if not found
     */
    public static Field findField(Class klass, String fieldName, Class fieldType) {
        return findField(klass, fieldName, field -> Objects.equals(fieldType, field.getType()));
    }

    /**
     * Find the declared {@link Field} by its' name
     *
     * @param klass      {@link Class class} to find
     * @param fieldName  the name of {@link Field field}
     * @param predicates zero or more {@link Predicate}
     * @return null if not found
     */
    public static Field findField(Class klass, String fieldName, Predicate... predicates) {
        Field field = findField(klass, fieldName);
        return and(predicates).test(field) ? field : null;
    }

    /**
     * Get the static {@link Field} Value
     *
     * @param klass     {@link Class class} to find
     * @param fieldName the name of {@link Field field}
     * @return null if field is null or get failed
     */
    public static  T getStaticFieldValue(Class klass, String fieldName) {
        Field field = findField(klass, fieldName);
        return getStaticFieldValue(field);
    }

    /**
     * Get the static {@link Field} Value
     *
     * @param field {@link Field}
     * @return null if field is null or get failed
     */
    public static  T getStaticFieldValue(Field field) {
        return getFieldValue(null, field);
    }

    /**
     * Set the value to static {@link Field}
     *
     * @param klass      the class declared the field
     * @param fieldName  the name of {@link Field}
     * @param fieldValue the value of {@link Field}
     */
    public static void setStaticFieldValue(Class klass, String fieldName, Object fieldValue) {
        Field field = findField(klass, fieldName);
        setFieldValue(null, field, fieldValue);
    }

    public static Set findAllFields(Class declaredClass, Predicate... fieldFilters) {
        Set allFields = new LinkedHashSet<>(asList(declaredClass.getFields()));
        for (Class superType : getAllInheritedTypes(declaredClass)) {
            allFields.addAll(asList(superType.getFields()));
        }
        return filter(allFields, and(fieldFilters));
    }

    public static Set findAllDeclaredFields(Class declaredClass, Predicate... fieldFilters) {
        Set allDeclaredFields = new LinkedHashSet<>(asList(declaredClass.getDeclaredFields()));
        for (Class superType : getAllInheritedTypes(declaredClass)) {
            allDeclaredFields.addAll(asList(superType.getDeclaredFields()));
        }
        return filter(allDeclaredFields, and(fieldFilters));
    }

    /**
     * Like the {@link Class#getDeclaredField(String)} method without throwing any {@link Exception}
     *
     * @param declaredClass the declared class
     * @param fieldName     the name of {@link Field}
     * @return if can't be found, return null
     */
    public static Field getDeclaredField(Class declaredClass, String fieldName) {
        return execute(() -> declaredClass.getDeclaredField(fieldName));
    }

    /**
     * Get the value of the specified {@link Field}
     *
     * @param instance  the instance whose field should be modified
     * @param fieldName the name of {@link Field}
     * @return the value of  the specified {@link Field}
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V getFieldValue(Object instance, String fieldName) throws IllegalStateException, IllegalArgumentException {
        return getFieldValue(instance, findField(instance, fieldName));
    }


    /**
     * Get {@link Field} Value
     *
     * @param instance     the instance whose field should be modified
     * @param fieldName    field name
     * @param           field type
     * @param defaultValue default value
     * @return {@link Field} Value
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V getFieldValue(Object instance, String fieldName, V defaultValue) throws IllegalStateException, IllegalArgumentException {
        V value = getFieldValue(instance, fieldName);
        return value != null ? value : defaultValue;
    }

    /**
     * Get {@link Field} Value
     *
     * @param instance  the instance whose field should be modified
     * @param fieldName field name
     * @param fieldType field type
     * @param        field type
     * @return {@link Field} Value
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V getFieldValue(Object instance, String fieldName, Class fieldType) throws IllegalStateException, IllegalArgumentException {
        Field field = findField(instance.getClass(), fieldName, fieldType);
        return getFieldValue(instance, field);
    }

    /**
     * Get the value of the specified {@link Field}
     *
     * @param instance the instance whose field should be modified
     * @param field    {@link Field}
     * @return the value of  the specified {@link Field}
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V getFieldValue(Object instance, Field field) throws IllegalStateException, IllegalArgumentException {
        if (field == null) {
            return null;
        }

        V fieldValue = null;
        boolean accessible = false;
        try {
            accessible = trySetAccessible(field);
            fieldValue = (V) field.get(instance);
        } catch (IllegalAccessException e) {
            String errorMessage = format("The field[name : '{}' , type : '{}' , instance : {}] can't be accessed[accessible : {}]",
                    field.getName(), field.getType(), instance, accessible);
            throw new IllegalStateException(errorMessage, e);
        }

        return fieldValue;
    }

    /**
     * Set the value for the specified {@link Field}
     *
     * @param instance  the instance whose field should be modified
     * @param fieldName the name of {@link Field}
     * @param value     the value of field to be set
     * @return the previous value of the specified {@link Field}
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V setFieldValue(Object instance, String fieldName, V value) throws IllegalStateException, IllegalArgumentException {
        return setFieldValue(instance, findField(instance, fieldName), value);
    }

    /**
     * Set the value for the specified {@link Field}
     *
     * @param instance the instance whose field should be modified
     * @param field    {@link Field}
     * @param value    the value of field to be set
     * @return the previous value of the specified {@link Field}
     * @throws IllegalStateException    if this Field object is enforcing Java language access control and the underlying
     *                                  field is inaccessible.
     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring
     *                                  the underlying field (or a subclass or implementor thereof).
     */
    public static  V setFieldValue(Object instance, Field field, V value) throws IllegalStateException, IllegalArgumentException {
        if (field == null) {
            return null;
        }

        V previousValue = null;
        boolean accessible = false;
        try {
            accessible = trySetAccessible(field);
            previousValue = (V) field.get(instance);
            if (!Objects.equals(previousValue, value)) {
                field.set(instance, value);
            }
        } catch (IllegalAccessException e) {
            String errorMessage = format("The field[name : '{}' , type : '{}' , instance : {}] can't be accessed[accessible : {}]",
                    field.getName(), field.getType(), instance, accessible);
            throw new IllegalStateException(errorMessage, e);
        } catch (IllegalArgumentException e) {
            String errorMessage = format("The instance[{}] can't match the field[name : '{}' , type : '{}']",
                    instance, field.getName(), field.getType());
            throw new IllegalArgumentException(errorMessage, e);
        }

        return previousValue;
    }

    /**
     * Assert Field type match
     *
     * @param instance     Object
     * @param fieldName    field name
     * @param expectedType expected type
     * @throws IllegalArgumentException if type is not matched
     */
    public static void assertFieldMatchType(Object instance, String fieldName, Class expectedType) throws IllegalArgumentException {
        Class type = instance.getClass();
        Field field = findField(type, fieldName);
        Class fieldType = field.getType();
        if (!expectedType.isAssignableFrom(fieldType)) {
            String message = format("The type['{}'] of field['{}'] in Class['{}'] can't match expected type['{}']", fieldType.getName(), fieldName, type.getName(), expectedType.getName());
            throw new IllegalArgumentException(message);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy