18
18
import java .io .Serializable ;
19
19
import java .lang .invoke .MethodHandles ;
20
20
import java .lang .invoke .MethodHandles .Lookup ;
21
+ import java .lang .invoke .MethodType ;
21
22
import java .lang .reflect .Constructor ;
22
23
import java .lang .reflect .InvocationHandler ;
23
24
import java .lang .reflect .Method ;
@@ -35,7 +36,8 @@ public class MapperProxy<T> implements InvocationHandler, Serializable {
35
36
private static final long serialVersionUID = -6424540398559729838L ;
36
37
private static final int ALLOWED_MODES = MethodHandles .Lookup .PRIVATE | MethodHandles .Lookup .PROTECTED
37
38
| MethodHandles .Lookup .PACKAGE | MethodHandles .Lookup .PUBLIC ;
38
- private static Constructor <Lookup > lookupConstructor ;
39
+ private static final Constructor <Lookup > lookupConstructor ;
40
+ private static final Method privateLookupInMethod ;
39
41
private final SqlSession sqlSession ;
40
42
private final Class <T > mapperInterface ;
41
43
private final Map <Method , MapperMethod > methodCache ;
@@ -47,17 +49,29 @@ public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method,
47
49
}
48
50
49
51
static {
52
+ Method privateLookupIn ;
50
53
try {
51
- lookupConstructor = MethodHandles .Lookup . class .getDeclaredConstructor ( Class .class , int .class );
54
+ privateLookupIn = MethodHandles .class .getMethod ( "privateLookupIn" , Class .class , MethodHandles . Lookup .class );
52
55
} catch (NoSuchMethodException e ) {
56
+ privateLookupIn = null ;
57
+ }
58
+ privateLookupInMethod = privateLookupIn ;
59
+
60
+ Constructor <Lookup > lookup = null ;
61
+ if (privateLookupInMethod == null ) {
62
+ // JDK 1.8
53
63
try {
54
- // Since Java 14+8
55
- lookupConstructor = MethodHandles .Lookup .class .getDeclaredConstructor (Class .class , Class .class , int .class );
56
- } catch (NoSuchMethodException e2 ) {
57
- throw new IllegalStateException ("No known constructor found in java.lang.invoke.MethodHandles.Lookup." , e2 );
64
+ lookup = MethodHandles .Lookup .class .getDeclaredConstructor (Class .class , int .class );
65
+ lookup .setAccessible (true );
66
+ } catch (NoSuchMethodException e ) {
67
+ throw new IllegalStateException (
68
+ "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles." ,
69
+ e );
70
+ } catch (Throwable t ) {
71
+ lookup = null ;
58
72
}
59
73
}
60
- lookupConstructor . setAccessible ( true ) ;
74
+ lookupConstructor = lookup ;
61
75
}
62
76
63
77
@ Override
@@ -66,7 +80,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
66
80
if (Object .class .equals (method .getDeclaringClass ())) {
67
81
return method .invoke (this , args );
68
82
} else if (method .isDefault ()) {
69
- return invokeDefaultMethod (proxy , method , args );
83
+ if (privateLookupInMethod == null ) {
84
+ return invokeDefaultMethodJava8 (proxy , method , args );
85
+ } else {
86
+ return invokeDefaultMethodJava9 (proxy , method , args );
87
+ }
70
88
}
71
89
} catch (Throwable t ) {
72
90
throw ExceptionUtil .unwrapThrowable (t );
@@ -76,19 +94,23 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
76
94
}
77
95
78
96
private MapperMethod cachedMapperMethod (Method method ) {
79
- return methodCache .computeIfAbsent (method , k -> new MapperMethod (mapperInterface , method , sqlSession .getConfiguration ()));
97
+ return methodCache .computeIfAbsent (method ,
98
+ k -> new MapperMethod (mapperInterface , method , sqlSession .getConfiguration ()));
80
99
}
81
100
82
- private Object invokeDefaultMethod (Object proxy , Method method , Object [] args )
101
+ private Object invokeDefaultMethodJava9 (Object proxy , Method method , Object [] args )
83
102
throws Throwable {
84
103
final Class <?> declaringClass = method .getDeclaringClass ();
85
- final Lookup lookup ;
86
- if (lookupConstructor .getParameterCount () == 2 ) {
87
- lookup = lookupConstructor .newInstance (declaringClass , ALLOWED_MODES );
88
- } else {
89
- // SInce JDK 14+8
90
- lookup = lookupConstructor .newInstance (declaringClass , null , ALLOWED_MODES );
91
- }
92
- return lookup .unreflectSpecial (method , declaringClass ).bindTo (proxy ).invokeWithArguments (args );
104
+ return ((Lookup ) privateLookupInMethod .invoke (null , declaringClass , MethodHandles .lookup ()))
105
+ .findSpecial (declaringClass , method .getName (),
106
+ MethodType .methodType (method .getReturnType (), method .getParameterTypes ()), declaringClass )
107
+ .bindTo (proxy ).invokeWithArguments (args );
108
+ }
109
+
110
+ private Object invokeDefaultMethodJava8 (Object proxy , Method method , Object [] args )
111
+ throws Throwable {
112
+ final Class <?> declaringClass = method .getDeclaringClass ();
113
+ return lookupConstructor .newInstance (declaringClass , ALLOWED_MODES ).unreflectSpecial (method , declaringClass )
114
+ .bindTo (proxy ).invokeWithArguments (args );
93
115
}
94
116
}
0 commit comments