]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/common/ReflectionHelper.java
Setup for 1.16.3 Fabric
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / common / ReflectionHelper.java
1 package com.irtimaled.bbor.common;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.ParameterizedType;
6 import java.lang.reflect.Type;
7 import java.util.function.BiFunction;
8 import java.util.function.Function;
9
10 public class ReflectionHelper {
11     public static <T, R> Function<T, R> getPrivateFieldGetter(Class<?> clazz, Type fieldType, Type... genericTypeArguments) {
12         Field field = getGenericField(clazz, fieldType, genericTypeArguments);
13         if (field == null) return obj -> null;
14
15         field.setAccessible(true);
16         return obj -> {
17             try {
18                 return (R) field.get(obj);
19             } catch (IllegalAccessException ignored) {
20                 return null;
21             }
22         };
23     }
24
25     public static Field getGenericField(Class<?> clazz, Type fieldType, Type[] genericTypeArguments) {
26         Field field = findField(clazz, fieldType, genericTypeArguments);
27         return field != null ? field : findField(clazz, fieldType, null);
28     }
29
30     private static Field findField(Class<?> clazz, Type fieldType, Type[] genericTypeArguments) {
31         for (Field field : clazz.getDeclaredFields()) {
32             Type type = field.getGenericType();
33             ParameterizedType genericType = TypeHelper.as(type, ParameterizedType.class);
34             if (genericType == null) {
35                 if (type != fieldType || genericTypeArguments.length > 0) continue;
36                 return field;
37             }
38
39             Type rawType = genericType.getRawType();
40             if (rawType != fieldType) continue;
41
42             if (genericTypeArguments == null) return field;
43
44             Type[] actualTypeArguments = genericType.getActualTypeArguments();
45             if (!typesMatch(genericTypeArguments, actualTypeArguments)) continue;
46
47             return field;
48         }
49         return null;
50     }
51
52     private static boolean typesMatch(Type[] left, Type[] right) {
53         if (left.length != right.length) return false;
54
55         for (int index = 0; index < right.length; index++) {
56             if (right[index] != left[index]) {
57                 return false;
58             }
59         }
60         return true;
61     }
62
63     public static <T, R, S> BiFunction<T, R, S> getPrivateInstanceBuilder(Class<S> clazz, Class<T> parameter1, Class<R> parameter2) {
64         Constructor<S> constructor = findConstructor(clazz, parameter1, parameter2);
65         if (constructor == null) return (obj1, obj2) -> null;
66
67         constructor.setAccessible(true);
68         return (obj1, obj2) -> {
69             try {
70                 return (S) constructor.newInstance(obj1, obj2);
71             } catch (Exception ignored) {
72                 return null;
73             }
74         };
75     }
76
77     private static <T> Constructor<T> findConstructor(Class<T> clazz, Class<?>... parameters) {
78         try {
79             return clazz.getDeclaredConstructor(parameters);
80         } catch (NoSuchMethodException ignored) {
81             return null;
82         }
83     }
84 }