5
5
6
6
import java .lang .invoke .MethodHandles ;
7
7
import java .lang .reflect .Field ;
8
+ import java .lang .reflect .InvocationTargetException ;
8
9
import java .lang .reflect .Method ;
9
10
import java .lang .reflect .Proxy ;
11
+ import java .util .HashMap ;
12
+ import java .util .Map ;
10
13
11
14
/**
12
15
* Utilities for reflections
15
18
*/
16
19
public class ReflectionUtils {
17
20
18
- private static final MethodHandles .Lookup lookup ;
19
-
20
- static {
21
- try {
22
- Field field = MethodHandles .Lookup .class .getDeclaredField ("IMPL_LOOKUP" );
23
- field .setAccessible (true );
24
-
25
- lookup = (MethodHandles .Lookup ) field .get (null );
26
- } catch (NoSuchFieldException | IllegalAccessException e ) {
27
- throw new InvalidConfigException ("Could not get MethodHandles.Lookup" , e );
28
- }
29
- }
21
+ private static final Map <Class <?>, MethodHandles .Lookup > lookups = new HashMap <>();
30
22
31
23
/**
32
24
* Allows to get default value of method from interface
@@ -36,7 +28,7 @@ public class ReflectionUtils {
36
28
public static Object getDefaultValue (Method method ) {
37
29
try {
38
30
Class <?> clazz = method .getDeclaringClass ();
39
- return lookup
31
+ return getLookup ( clazz )
40
32
.in (clazz )
41
33
.unreflectSpecial (method , clazz )
42
34
.bindTo (createHelperProxy (method .getDeclaringClass ()))
@@ -46,6 +38,46 @@ public static Object getDefaultValue(Method method) {
46
38
}
47
39
}
48
40
41
+ /**
42
+ * Creates private lookup for given class
43
+ * For Java 8 it gets value of MethodHandles.Lookup.IMPL_LOOKUP, for newer versions invokes MethodHandles.privateLookupIn()
44
+ * Reference: https://github.com/OpenFeign/feign/commit/3494a76f160d6622129d59a6c79358dbccf6e6d6
45
+ * @param clazz for which you want to create lookup
46
+ * @return instance of lookup
47
+ */
48
+ private static MethodHandles .Lookup createLookup (Class <?> clazz ) {
49
+ boolean oldJava = isOldJava ();
50
+
51
+ try {
52
+ if (oldJava ) {
53
+ Field field = MethodHandles .Lookup .class .getDeclaredField ("IMPL_LOOKUP" );
54
+ field .setAccessible (true );
55
+
56
+ return (MethodHandles .Lookup ) field .get (null );
57
+ }
58
+
59
+ Object privateLookupIn = MethodHandles .class .getMethod ("privateLookupIn" , Class .class , MethodHandles .Lookup .class )
60
+ .invoke (null , clazz , MethodHandles .lookup ());
61
+
62
+ return (MethodHandles .Lookup ) privateLookupIn ;
63
+ } catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException | InvocationTargetException e ) {
64
+ throw new InvalidConfigException ("Could not get MethodHandles.Lookup for " + clazz .getName () + " (legacy way: " + oldJava + ")" , e );
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Gets lookup for given class from cache or create new one if it doesn't exist
70
+ * @param clazz for which you want to get lookup
71
+ * @return instance of lookup for given class
72
+ */
73
+ private static MethodHandles .Lookup getLookup (Class <?> clazz ) {
74
+ if (!lookups .containsKey (clazz )) {
75
+ lookups .put (clazz , createLookup (clazz ));
76
+ }
77
+
78
+ return lookups .get (clazz );
79
+ }
80
+
49
81
/**
50
82
* Creates instance of proxy
51
83
* @param clazz class which you want to get instance of
@@ -56,6 +88,15 @@ private static Object createHelperProxy(Class<?> clazz) {
56
88
(Object object , Method method , Object [] args ) -> null );
57
89
}
58
90
91
+ /**
92
+ * Check Java version
93
+ * @return true for Java 8, false for Java 9 or newer
94
+ */
95
+ private static boolean isOldJava () {
96
+ String javaVersion = System .getProperty ("java.version" );
97
+ return javaVersion .startsWith ("1.8" ) || javaVersion .startsWith ("8" );
98
+ }
99
+
59
100
/**
60
101
* Check bukkit versions
61
102
* @return false for Minecraft 1.12 or older, true for 1.13 or newer
0 commit comments