
org.ttzero.excel.util.ReflectUtil Maven / Gradle / Ivy
/*
* Copyright (c) 2017-2019, [email protected] All Rights Reserved.
*
* Licensed 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 org.ttzero.excel.util;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
/**
* @author guanquan.wang at 2019-08-15 21:02
*/
public class ReflectUtil {
private ReflectUtil() {
}
/**
* List all declared fields that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @return all declared fields
*/
public static Field[] listDeclaredFields(Class> beanClass) {
return listDeclaredFields(beanClass, Object.class);
}
/**
* List all declared fields that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @return all declared fields
*/
public static Field[] listDeclaredFields(Class> beanClass, Class> stopClass) {
Field[] fields = beanClass.getDeclaredFields();
int i = fields.length, last = 0;
for (; (beanClass = beanClass.getSuperclass()) != stopClass; ) {
Field[] subFields = beanClass.getDeclaredFields();
if (subFields.length > 0) {
if (subFields.length > last) {
Field[] tmp = new Field[fields.length + subFields.length];
System.arraycopy(fields, 0, tmp, 0, i);
fields = tmp;
last = tmp.length - i;
}
System.arraycopy(subFields, 0, fields, i, subFields.length);
i += subFields.length;
last -= subFields.length;
}
}
return fields;
}
/**
* List all declared fields that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param predicate A field filter
* @return all declared fields
*/
public static Field[] listDeclaredFields(Class> beanClass, Predicate predicate) {
return listDeclaredFields(beanClass, Object.class, predicate);
}
/**
* List all declared fields that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @param predicate A field filter
* @return all declared fields
*/
public static Field[] listDeclaredFields(Class> beanClass, Class> stopClass, Predicate predicate) {
Field[] fields = listDeclaredFields(beanClass, stopClass);
return fieldFilter(fields, predicate);
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listDeclaredMethods(Class> beanClass)
throws IntrospectionException {
return listDeclaredMethods(beanClass, Object.class);
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listDeclaredMethods(Class> beanClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listDeclaredMethods(beanClass);
return methodFilter(methods, predicate);
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listDeclaredMethods(Class> beanClass, Class> stopClass)
throws IntrospectionException {
MethodDescriptor[] methodDescriptors = Introspector.getBeanInfo(beanClass, stopClass).getMethodDescriptors();
Method[] allMethods = beanClass.getMethods();
Method[] methods;
if (methodDescriptors.length > 0) {
methods = new Method[methodDescriptors.length];
for (int i = 0; i < methodDescriptors.length; i++) {
int index = indexOf(allMethods, methodDescriptors[i].getMethod());
methods[i] = index >= 0 ? allMethods[index] : methodDescriptors[i].getMethod();
}
} else methods = new Method[0];
return methods;
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listDeclaredMethods(Class> beanClass, Class> stopClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listDeclaredMethods(beanClass, stopClass);
return methodFilter(methods, predicate);
}
/**
* List all declared read methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listReadMethods(Class> beanClass) throws IntrospectionException {
return listReadMethods(beanClass, Object.class);
}
/**
* List all declared read methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listReadMethods(Class> beanClass, Class> stopClass)
throws IntrospectionException {
Method[] methods = listDeclaredMethods(beanClass, stopClass);
int n = 0;
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getParameterCount() == 0) {
Class> returnType = method.getReturnType();
if (returnType != void.class && returnType != Void.class) {
methods[n++] = method;
}
}
}
return n < methods.length ? Arrays.copyOf(methods, n) : methods;
}
/**
* List all declared read methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listReadMethods(Class> beanClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listReadMethods(beanClass);
return methodFilter(methods, predicate);
}
/**
* List all declared read methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listReadMethods(Class> beanClass, Class> stopClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listReadMethods(beanClass, stopClass);
return methodFilter(methods, predicate);
}
/**
* List all declared write methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listWriteMethods(Class> beanClass) throws IntrospectionException {
return listWriteMethods(beanClass, Object.class);
}
/**
* List all declared write methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listWriteMethods(Class> beanClass, Class> stopClass)
throws IntrospectionException {
Method[] methods = listDeclaredMethods(beanClass, stopClass);
Field[] fields = listDeclaredFields(beanClass, stopClass);
Set tmp = new HashSet<>();
for (Field field : fields)
tmp.add("set" + field.getName().toLowerCase());
int n = 0;
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
Class> returnType = method.getReturnType();
if (method.getParameterCount() == 1 && (returnType == void.class || returnType == Void.class)
&& tmp.contains(method.getName().toLowerCase())) {
methods[n++] = method;
}
}
return n < methods.length ? Arrays.copyOf(methods, n) : methods;
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listWriteMethods(Class> beanClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listWriteMethods(beanClass);
return methodFilter(methods, predicate);
}
/**
* List all declared methods that contains all supper class
*
* @param beanClass The bean class to be analyzed.
* @param stopClass The base class at which to stop the analysis. Any
* methods/properties/events in the stopClass or in its base classes
* will be ignored in the analysis.
* @param predicate A method filter
* @return all declared method
* @throws IntrospectionException happens during introspection error
*/
public static Method[] listWriteMethods(Class> beanClass, Class> stopClass, Predicate predicate)
throws IntrospectionException {
Method[] methods = listWriteMethods(beanClass, stopClass);
return methodFilter(methods, predicate);
}
/**
* Found source method in methods array witch the source method
* equals it or the has a same method name and return-type and same parameters
*
* @param methods the array methods to be found
* @param source the source method
* @return the index in method array
*/
public static int indexOf(Method[] methods, Method source) {
int i = 0;
for (Method method : methods) {
if (method == null) {
i++;
continue;
}
if (method.equals(source)) {
return i;
}
if (method.getName().equals(source.getName())
&& method.getReturnType() == source.getReturnType()
&& parameterDeepEquals(method.getParameters(), source.getParameters())) {
return i;
}
i++;
}
return -1;
}
public static int mapping(Method[] writeMethods, Map tmp
, PropertyDescriptor[] propertyDescriptors, Method[] mergedMethods) {
if (writeMethods == null) {
for (int i = 1; i < propertyDescriptors.length; i++) {
PropertyDescriptor pd = propertyDescriptors[i];
tmp.put(pd.getName(), mergedMethods[i]);
}
} else {
int i;
for (int j = 0; j < mergedMethods.length; j++) {
i = mergedMethods[j] != null ? indexOf(writeMethods, mergedMethods[j]) : -1;
if (i >= 0) {
writeMethods[i] = null;
}
tmp.put(propertyDescriptors[j].getName(), mergedMethods[j]);
}
i = 0;
for (int j = 0; j < writeMethods.length; j++) {
if (writeMethods[j] != null) {
writeMethods[i++] = writeMethods[j];
}
}
return i;
}
return 0;
}
// Do Filter
private static Method[] methodFilter(Method[] methods, Predicate predicate) {
int n = 0;
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (predicate.test(method)) {
if (i != n) methods[n] = method;
n++;
}
}
return n < methods.length ? Arrays.copyOf(methods, n) : methods;
}
private static Field[] fieldFilter(Field[] fields, Predicate predicate) {
int n = 0;
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
field.setAccessible(true);
if (predicate.test(field)) {
if (i != n) fields[n] = field;
n++;
}
}
return n < fields.length ? Arrays.copyOf(fields, n) : fields;
}
// Parameter deep compare
private static boolean parameterDeepEquals(Parameter[] aClass, Parameter[] bClass) {
boolean equals = aClass.length == bClass.length;
if (equals) {
for (int i = 0; i < aClass.length; i++) {
if (!(equals = aClass[i].equals(bClass[i])
|| aClass[i].getType() == bClass[i].getType())
) {
break;
}
}
}
return equals;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy