1
1
/*
2
- * Copyright 2009-2021 the original author or authors.
2
+ * Copyright 2009-2022 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
15
15
*/
16
16
package org .apache .ibatis .reflection ;
17
17
18
+ import java .lang .invoke .MethodHandle ;
19
+ import java .lang .invoke .MethodHandles ;
20
+ import java .lang .invoke .MethodType ;
18
21
import java .lang .reflect .Array ;
19
22
import java .lang .reflect .Constructor ;
20
23
import java .lang .reflect .Field ;
50
53
*/
51
54
public class Reflector {
52
55
56
+ private static final MethodHandle isRecordMethodHandle = getIsRecordMethodHandle ();
53
57
private final Class <?> type ;
54
58
private final String [] readablePropertyNames ;
55
59
private final String [] writablePropertyNames ;
@@ -65,10 +69,9 @@ public Reflector(Class<?> clazz) {
65
69
type = clazz ;
66
70
addDefaultConstructor (clazz );
67
71
Method [] classMethods = getClassMethods (clazz );
68
- if (this .isRecordType ()) {
69
- addAccessorMethods (classMethods );
70
- }
71
- else {
72
+ if (isRecord (type )) {
73
+ addRecordGetMethods (classMethods );
74
+ } else {
72
75
addGetMethods (classMethods );
73
76
addSetMethods (classMethods );
74
77
addFields (clazz );
@@ -83,20 +86,11 @@ public Reflector(Class<?> clazz) {
83
86
}
84
87
}
85
88
86
- // java.lang.Record
87
-
88
- private boolean isRecordType () {
89
- Class <?> parent = this .type .getSuperclass ();
90
- return null != parent && "java.lang.Record" .equals (parent .getName ());
91
- }
92
-
93
- private void addAccessorMethods (Method [] methods ) {
89
+ private void addRecordGetMethods (Method [] methods ) {
94
90
Arrays .stream (methods ).filter (m -> m .getParameterTypes ().length == 0 )
95
91
.forEach (m -> addGetMethod (m .getName (), m , false ));
96
92
}
97
93
98
- // non-record
99
-
100
94
private void addDefaultConstructor (Class <?> clazz ) {
101
95
Constructor <?>[] constructors = clazz .getDeclaredConstructors ();
102
96
Arrays .stream (constructors ).filter (constructor -> constructor .getParameterTypes ().length == 0 )
@@ -151,9 +145,6 @@ private void addGetMethod(String name, Method method, boolean isAmbiguous) {
151
145
getMethods .put (name , invoker );
152
146
Type returnType = TypeParameterResolver .resolveReturnType (method , type );
153
147
getTypes .put (name , typeToClass (returnType ));
154
- // if (this.isRecordType()) {
155
- // System.out.println("record " + this.type.getSimpleName() + " addGetMethod " + name + " returning " + returnType);
156
- // }
157
148
}
158
149
159
150
private void addSetMethods (Method [] methods ) {
@@ -467,4 +458,25 @@ public boolean hasGetter(String propertyName) {
467
458
public String findPropertyName (String name ) {
468
459
return caseInsensitivePropertyMap .get (name .toUpperCase (Locale .ENGLISH ));
469
460
}
461
+
462
+ /**
463
+ * Class.isRecord() alternative for Java 15 and older.
464
+ */
465
+ private static boolean isRecord (Class <?> clazz ) {
466
+ try {
467
+ return isRecordMethodHandle != null && (boolean )isRecordMethodHandle .invokeExact (clazz );
468
+ } catch (Throwable e ) {
469
+ throw new ReflectionException ("Failed to invoke 'Class.isRecord()'." , e );
470
+ }
471
+ }
472
+
473
+ private static MethodHandle getIsRecordMethodHandle () {
474
+ MethodHandles .Lookup lookup = MethodHandles .lookup ();
475
+ MethodType mt = MethodType .methodType (boolean .class );
476
+ try {
477
+ return lookup .findVirtual (Class .class , "isRecord" , mt );
478
+ } catch (NoSuchMethodException | IllegalAccessException e ) {
479
+ return null ;
480
+ }
481
+ }
470
482
}
0 commit comments