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);
}
}
}