001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.utils;
017
018import com.jfinal.kit.LogKit;
019
020import java.lang.reflect.Field;
021import java.lang.reflect.InvocationTargetException;
022import java.lang.reflect.Method;
023import java.util.Arrays;
024import java.util.LinkedList;
025import java.util.List;
026import java.util.function.Predicate;
027
028/**
029 * 反射相关操作的工具类
030 */
031public class ReflectUtil {
032
033    public static <T> T getStaticFieldValue(Class<?> dClass, String fieldName) {
034        return getFieldValue(dClass, fieldName, null);
035    }
036
037    public static <T> T getFieldValue(Object getFrom, String fieldName) {
038        return getFieldValue(getFrom.getClass(), fieldName, getFrom);
039    }
040
041    private static <T> T getFieldValue(Class<?> dClass, String fieldName, Object getFrom) {
042        try {
043            if (StrUtil.isBlank(fieldName)) {
044                throw new IllegalArgumentException("fieldName must not be null or empty.");
045            }
046            Field field = searchField(dClass, f -> f.getName().equals(fieldName));
047            if (field == null) {
048                throw new NoSuchFieldException(fieldName);
049            }
050
051            return getFileValue(getFrom, field);
052
053        } catch (NoSuchFieldException e) {
054            throw new RuntimeException(e);
055        }
056    }
057
058    private static <T> T getFileValue(Object getFrom, Field field) {
059        boolean accessible = field.isAccessible();
060        try {
061            field.setAccessible(true);
062            return (T) field.get(getFrom);
063        } catch (IllegalAccessException e) {
064            LogKit.error(e.toString(), e);
065        } finally {
066            field.setAccessible(accessible);
067        }
068        return null;
069    }
070
071
072    public static void setStaticFieldValue(Class<?> dClass, String fieldName, Object value) {
073        setFieldValue(dClass, null, fieldName, value);
074    }
075
076
077    public static void setFieldValue(Object setTo, String fieldName, Object value) {
078        setFieldValue(setTo.getClass(), setTo, fieldName, value);
079    }
080
081
082    private static void setFieldValue(Class<?> dClass, Object setTo, String fieldName, Object value) {
083        setFieldValue(dClass, setTo, f -> f.getName().equals(fieldName), value);
084    }
085
086
087    private static void setFieldValue(Class<?> dClass, Object setTo, Predicate<Field> filter, Object value) {
088        Field field = searchField(dClass, filter);
089        if (field == null) {
090            throw new IllegalArgumentException("No such field");
091        }
092
093        setFieldValue(setTo, value, field);
094    }
095
096    public static void setFieldValue(Object setTo, Object value, Field field) {
097        final boolean accessible = field.isAccessible();
098        try {
099            field.setAccessible(true);
100            field.set(setTo, value);
101        } catch (IllegalAccessException e) {
102            LogKit.error(e.toString(), e);
103        } finally {
104            field.setAccessible(accessible);
105        }
106    }
107
108
109    public static Field searchField(Class<?> dClass, Predicate<Field> filter) {
110        if (dClass == null) {
111            return null;
112        }
113        Field[] fields = dClass.getDeclaredFields();
114        for (Field field : fields) {
115            if (filter.test(field)) {
116                return field;
117            }
118        }
119        return searchField(dClass.getSuperclass(), filter);
120    }
121
122
123    public static List<Field> searchFieldList(Class<?> dClass, Predicate<Field> filter) {
124        List<Field> fields = new LinkedList<>();
125        doSearchFieldList(dClass, filter, fields);
126        return fields;
127    }
128
129
130    private static void doSearchFieldList(Class<?> dClass, Predicate<Field> filter, List<Field> searchToList) {
131        if (dClass == null || dClass == Object.class) {
132            return;
133        }
134
135        Field[] fields = dClass.getDeclaredFields();
136        if (fields.length > 0) {
137            if (filter != null) {
138                for (Field field : fields) {
139                    if (filter.test(field)) {
140                        searchToList.add(field);
141                    }
142                }
143            } else {
144                searchToList.addAll(Arrays.asList(fields));
145            }
146        }
147
148        doSearchFieldList(dClass.getSuperclass(), filter, searchToList);
149    }
150
151
152    public static Method searchMethod(Class<?> dClass, Predicate<Method> filter) {
153        if (dClass == null) {
154            return null;
155        }
156        Method[] methods = dClass.getDeclaredMethods();
157        for (Method method : methods) {
158            if (filter.test(method)) {
159                return method;
160            }
161        }
162        return searchMethod(dClass.getSuperclass(), filter);
163    }
164
165
166    public static List<Method> searchMethodList(Class<?> dClass, Predicate<Method> filter) {
167        List<Method> methods = new LinkedList<>();
168        doSearchMethodList(dClass, filter, methods);
169        return methods;
170    }
171
172
173    private static void doSearchMethodList(Class<?> dClass, Predicate<Method> filter, List<Method> searchToList) {
174        if (dClass == null) {
175            return;
176        }
177        Method[] methods = dClass.getDeclaredMethods();
178        if (methods.length > 0) {
179            if (filter != null) {
180                for (Method method : methods) {
181                    if (filter.test(method)) {
182                        searchToList.add(method);
183                    }
184                }
185            } else {
186                searchToList.addAll(Arrays.asList(methods));
187            }
188        }
189
190        doSearchMethodList(dClass.getSuperclass(), filter, searchToList);
191    }
192
193
194    public static <T> T invokeStaticMethod(Class<?> dClass, String methodName, Object... args) {
195        return invokeStaticMethod(dClass, m -> m.getName().equals(methodName), args);
196    }
197
198
199    public static <T> T invokeStaticMethod(Class<?> dClass, Predicate<Method> filter, Object... args) {
200        Method method = searchMethod(dClass, filter);
201        if (method == null) {
202            throw new IllegalArgumentException("No such method.");
203        }
204        return invokeMethod(null, method, args);
205    }
206
207
208    public static <T> T invokeMethod(Object obj, String methodName, Object... args) {
209        return invokeMethod(obj, m -> m.getName().equals(methodName), args);
210    }
211
212
213    public static <T> T invokeMethod(Object obj, Predicate<Method> filter, Object... args) {
214        Method method = searchMethod(obj.getClass(), filter);
215        if (method == null) {
216            throw new IllegalArgumentException("No such method.");
217        }
218        return invokeMethod(obj, method, args);
219    }
220
221
222    public static <T> T invokeMethod(Object obj, Method method, Object... args) {
223        final boolean accessible = method.isAccessible();
224        try {
225            method.setAccessible(true);
226            return (T) method.invoke(obj, args);
227        } catch (IllegalAccessException | InvocationTargetException e) {
228            LogKit.error(e.toString(), e);
229        } finally {
230            method.setAccessible(accessible);
231        }
232        return null;
233    }
234
235}