15
15
import org .simpleflatmapper .ow2asm .Opcodes ;
16
16
import org .simpleflatmapper .util .FactoryClassLoader ;
17
17
18
+ import java .lang .invoke .MethodHandle ;
19
+ import java .lang .invoke .MethodHandles ;
18
20
import java .lang .reflect .Constructor ;
21
+ import java .lang .reflect .Method ;
19
22
import java .util .Arrays ;
20
23
import java .util .HashSet ;
21
24
import java .util .Iterator ;
31
34
32
35
public class AsmCharConsumerFactory extends CharConsumerFactory {
33
36
private static final AtomicInteger id = new AtomicInteger ();
34
-
37
+
35
38
public AbstractCharConsumer newCharConsumer (TextFormat textFormat , CharBuffer charBuffer , CellPreProcessor cellTransformer , boolean specialisedCharConsumer ) {
36
39
if (specialisedCharConsumer ) {
37
- SpecialisationKey key = new SpecialisationKey (cellTransformer .ignoreLeadingSpace (), textFormat , cellTransformer .getClass ());
38
40
39
- Constructor <? extends AbstractCharConsumer > constructor ;
41
+ MethodHandle constructor ;
40
42
41
- if (key .equals (RFC4180 )) {
42
- constructor = RFC4180_CC ;
43
- } else {
44
- constructor = specialisedCharConsumers .get (key );
45
- if (constructor == null && specialisedCharConsumers .size () < 64 ) {
46
- constructor = createNewSpecialisedCharConsumer (key );
43
+ if (RFC4180_CC != null && isRfc4180 (cellTransformer , textFormat )) {
44
+ try {
45
+ return (AbstractCharConsumer ) RFC4180_CC .invokeExact (charBuffer , textFormat , cellTransformer );
46
+ }catch (Throwable e ) {
47
+ throw new RuntimeException (e .getMessage (), e );
47
48
}
48
49
}
49
50
51
+ SpecialisationKey key = new SpecialisationKey (cellTransformer .ignoreLeadingSpace (), textFormat , cellTransformer .getClass ());
52
+
53
+ constructor = specialisedCharConsumers .get (key );
54
+ if (constructor == null && specialisedCharConsumers .size () < 64 ) {
55
+ constructor = createNewSpecialisedCharConsumer (key );
56
+ }
57
+
50
58
if (constructor != null ) {
51
59
try {
52
- return constructor .newInstance (charBuffer , key .textFormat , cellTransformer );
53
- } catch (Exception e ) {
60
+ return ( AbstractCharConsumer ) constructor .invokeExact (charBuffer , key .textFormat , cellTransformer );
61
+ } catch (Throwable e ) {
54
62
throw new RuntimeException (e .getMessage (), e );
55
63
}
56
64
}
@@ -60,16 +68,25 @@ public AbstractCharConsumer newCharConsumer(TextFormat textFormat, CharBuffer ch
60
68
61
69
}
62
70
71
+ private boolean isRfc4180 (CellPreProcessor cellTransformer , TextFormat textFormat ) {
72
+ return (RFC4180 .ignoreLeadingSpace == cellTransformer .ignoreLeadingSpace ())
73
+ && textFormat .equals (RFC4180 .textFormat )
74
+ && cellTransformer .getClass ().equals (RFC4180 .cellTransformer );
75
+ }
76
+
63
77
64
- private static Constructor <? extends AbstractCharConsumer > createNewSpecialisedCharConsumer (SpecialisationKey key ) {
78
+ private static MethodHandle createNewSpecialisedCharConsumer (SpecialisationKey key ) {
65
79
synchronized (lock ) {
66
- Constructor <? extends AbstractCharConsumer > constructor ;
80
+ MethodHandle constructor ;
67
81
constructor = specialisedCharConsumers .get (key );
68
82
if (constructor == null ) {
69
- if (specialisedCharConsumers .size () < 64 ) { // artificial limit to avoid DOS
70
- constructor = generateSpecialisedCharConsumer (key );
71
- if (constructor != null ) {
72
- specialisedCharConsumers .put (key , constructor );
83
+ if (specialisedCharConsumers .size () < 64 ) {
84
+ try {// artificial limit to avoid DOS
85
+ constructor = MethodHandles .lookup ().unreflect (generateSpecialisedCharConsumer (key ));
86
+ if (constructor != null ) {
87
+ specialisedCharConsumers .put (key , constructor );
88
+ }
89
+ } catch (Throwable t ) {
73
90
}
74
91
}
75
92
}
@@ -78,7 +95,7 @@ private static Constructor<? extends AbstractCharConsumer> createNewSpecialisedC
78
95
}
79
96
80
97
@ SuppressWarnings ("unchecked" )
81
- private static Constructor <? extends AbstractCharConsumer > generateSpecialisedCharConsumer (final SpecialisationKey key ) {
98
+ private static Method generateSpecialisedCharConsumer (final SpecialisationKey key ) {
82
99
try {
83
100
final String newName = "org/simpleflatmapper/lightningcsv/parser/Asm_"
84
101
+ (key .ignoreLeadingSpace ? "Ils_" : "" )
@@ -94,7 +111,7 @@ private static Constructor<? extends AbstractCharConsumer> generateSpecialisedCh
94
111
ClassReader reader = new ClassReader (
95
112
ConfigurableCharConsumer .class .getResourceAsStream ("ConfigurableCharConsumer.class" )
96
113
);
97
- ClassWriter writer = new ClassWriter (reader , ClassWriter .COMPUTE_MAXS |
114
+ ClassWriter writer = new ClassWriter (reader , ClassWriter .COMPUTE_MAXS |
98
115
ClassWriter .COMPUTE_FRAMES );
99
116
ClassVisitor visitor = new ClassVisitor (AsmUtils .API , writer ) {
100
117
@ Override
@@ -155,8 +172,8 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
155
172
156
173
} else {
157
174
return new MethodVisitor (AsmUtils .API , mv ) {
158
-
159
-
175
+
176
+
160
177
public void visitTypeInsn (int i , String s ) {
161
178
if (oldNames .contains (s )) {
162
179
s = newName ;
@@ -215,7 +232,7 @@ private String fix(String s) {
215
232
216
233
Class <?> clazz = classLoader .registerClass (className , bytes );
217
234
218
- return ( Constructor <? extends AbstractCharConsumer >) clazz .getConstructor ( CharBuffer .class , TextFormat .class , CellPreProcessor .class );
235
+ return clazz .getMethod ( "of" , CharBuffer .class , TextFormat .class , CellPreProcessor .class );
219
236
220
237
} catch (Exception e ) {
221
238
// ignore
@@ -227,19 +244,25 @@ private String fix(String s) {
227
244
private static final FactoryClassLoader classLoader = new FactoryClassLoader (AbstractCharConsumer .class .getClassLoader ());
228
245
private static final Object lock = new Object ();
229
246
private static final SpecialisationKey RFC4180 = new SpecialisationKey (false , new TextFormat (',' , '"' , '"' , false ), UnescapeCellPreProcessor .class );
230
- private static final Constructor <? extends AbstractCharConsumer > RFC4180_CC ;
247
+ private static final MethodHandle RFC4180_CC ;
231
248
232
249
static {
233
- RFC4180_CC = generateSpecialisedCharConsumer (RFC4180 );
250
+ MethodHandle methodHandle = null ;
251
+ try {
252
+ methodHandle = MethodHandles .lookup ().unreflect (generateSpecialisedCharConsumer (RFC4180 ));
253
+ } catch (Throwable t ) {
254
+ }
255
+ RFC4180_CC = methodHandle ;
234
256
}
235
257
236
- private static final ConcurrentHashMap <SpecialisationKey , Constructor <? extends AbstractCharConsumer > > specialisedCharConsumers =
237
- new ConcurrentHashMap <SpecialisationKey , Constructor <? extends AbstractCharConsumer > >();
258
+ private static final ConcurrentHashMap <SpecialisationKey , MethodHandle > specialisedCharConsumers =
259
+ new ConcurrentHashMap <SpecialisationKey , MethodHandle >();
238
260
239
261
private static class SpecialisationKey {
240
262
final boolean ignoreLeadingSpace ;
241
263
final TextFormat textFormat ;
242
264
final Class <?> cellTransformer ;
265
+
243
266
private SpecialisationKey (boolean ignoreLeadingSpace , TextFormat textFormat , Class <?> cellTransformer ) {
244
267
this .ignoreLeadingSpace = ignoreLeadingSpace ;
245
268
this .textFormat = textFormat ;
0 commit comments