@@ -133,6 +133,7 @@ public final class WhitelistLoader {
133
133
*/
134
134
public static Whitelist loadFromResourceFiles (Class <?> resource , String ... filepaths ) {
135
135
List <WhitelistClass > whitelistClasses = new ArrayList <>();
136
+ List <WhitelistBinding > whitelistBindings = new ArrayList <>();
136
137
137
138
// Execute a single pass through the whitelist text files. This will gather all the
138
139
// constructors, methods, augmented methods, and fields for each whitelisted class.
@@ -141,8 +142,9 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
141
142
int number = -1 ;
142
143
143
144
try (LineNumberReader reader = new LineNumberReader (
144
- new InputStreamReader (resource .getResourceAsStream (filepath ), StandardCharsets .UTF_8 ))) {
145
+ new InputStreamReader (resource .getResourceAsStream (filepath ), StandardCharsets .UTF_8 ))) {
145
146
147
+ String parseType = null ;
146
148
String whitelistClassOrigin = null ;
147
149
String javaClassName = null ;
148
150
boolean noImport = false ;
@@ -165,7 +167,11 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
165
167
// Ensure the final token of the line is '{'.
166
168
if (line .endsWith ("{" ) == false ) {
167
169
throw new IllegalArgumentException (
168
- "invalid class definition: failed to parse class opening bracket [" + line + "]" );
170
+ "invalid class definition: failed to parse class opening bracket [" + line + "]" );
171
+ }
172
+
173
+ if (parseType != null ) {
174
+ throw new IllegalArgumentException ("invalid definition: cannot embed class definition [" + line + "]" );
169
175
}
170
176
171
177
// Parse the Java class name.
@@ -178,41 +184,125 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
178
184
throw new IllegalArgumentException ("invalid class definition: failed to parse class name [" + line + "]" );
179
185
}
180
186
187
+ parseType = "class" ;
181
188
whitelistClassOrigin = "[" + filepath + "]:[" + number + "]" ;
182
189
javaClassName = tokens [0 ];
183
190
184
191
// Reset all the constructors, methods, and fields to support a new class.
185
192
whitelistConstructors = new ArrayList <>();
186
193
whitelistMethods = new ArrayList <>();
187
194
whitelistFields = new ArrayList <>();
195
+ } else if (line .startsWith ("static " )) {
196
+ // Ensure the final token of the line is '{'.
197
+ if (line .endsWith ("{" ) == false ) {
198
+ throw new IllegalArgumentException (
199
+ "invalid static definition: failed to parse static opening bracket [" + line + "]" );
200
+ }
188
201
189
- // Handle the end of a class, by creating a new WhitelistClass with all the previously gathered
190
- // constructors, methods, augmented methods, and fields, and adding it to the list of whitelisted classes.
202
+ if (parseType != null ) {
203
+ throw new IllegalArgumentException ("invalid definition: cannot embed static definition [" + line + "]" );
204
+ }
205
+
206
+ parseType = "static" ;
207
+
208
+ // Handle the end of a definition and reset all previously gathered values.
191
209
// Expects the following format: '}' '\n'
192
210
} else if (line .equals ("}" )) {
193
- if (javaClassName == null ) {
194
- throw new IllegalArgumentException ("invalid class definition: extraneous closing bracket" );
211
+ if (parseType == null ) {
212
+ throw new IllegalArgumentException ("invalid definition: extraneous closing bracket" );
195
213
}
196
214
197
- whitelistClasses .add (new WhitelistClass (whitelistClassOrigin , javaClassName , noImport ,
198
- whitelistConstructors , whitelistMethods , whitelistFields ));
215
+ // Create a new WhitelistClass with all the previously gathered constructors, methods,
216
+ // augmented methods, and fields, and add it to the list of whitelisted classes.
217
+ if ("class" .equals (parseType )) {
218
+ whitelistClasses .add (new WhitelistClass (whitelistClassOrigin , javaClassName , noImport ,
219
+ whitelistConstructors , whitelistMethods , whitelistFields ));
220
+
221
+ whitelistClassOrigin = null ;
222
+ javaClassName = null ;
223
+ noImport = false ;
224
+ whitelistConstructors = null ;
225
+ whitelistMethods = null ;
226
+ whitelistFields = null ;
227
+ }
199
228
200
- // Set all the variables to null to ensure a new class definition is found before other parsable values.
201
- whitelistClassOrigin = null ;
202
- javaClassName = null ;
203
- noImport = false ;
204
- whitelistConstructors = null ;
205
- whitelistMethods = null ;
206
- whitelistFields = null ;
229
+ // Reset the parseType.
230
+ parseType = null ;
207
231
208
- // Handle all other valid cases.
209
- } else {
232
+ // Handle static definition types.
233
+ // Expects the following format: ID ID '(' ( ID ( ',' ID )* )? ')' 'bound_to' ID '\n'
234
+ } else if ("static" .equals (parseType )) {
235
+ // Mark the origin of this parsable object.
236
+ String origin = "[" + filepath + "]:[" + number + "]" ;
237
+
238
+ // Parse the tokens prior to the method parameters.
239
+ int parameterStartIndex = line .indexOf ('(' );
240
+
241
+ if (parameterStartIndex == -1 ) {
242
+ throw new IllegalArgumentException (
243
+ "illegal static definition: start of method parameters not found [" + line + "]" );
244
+ }
245
+
246
+ String [] tokens = line .substring (0 , parameterStartIndex ).trim ().split ("\\ s+" );
247
+
248
+ String methodName ;
249
+
250
+ // Based on the number of tokens, look up the Java method name.
251
+ if (tokens .length == 2 ) {
252
+ methodName = tokens [1 ];
253
+ } else {
254
+ throw new IllegalArgumentException ("invalid method definition: unexpected format [" + line + "]" );
255
+ }
256
+
257
+ String returnCanonicalTypeName = tokens [0 ];
258
+
259
+ // Parse the method parameters.
260
+ int parameterEndIndex = line .indexOf (')' );
261
+
262
+ if (parameterEndIndex == -1 ) {
263
+ throw new IllegalArgumentException (
264
+ "illegal static definition: end of method parameters not found [" + line + "]" );
265
+ }
266
+
267
+ String [] canonicalTypeNameParameters =
268
+ line .substring (parameterStartIndex + 1 , parameterEndIndex ).replaceAll ("\\ s+" , "" ).split ("," );
269
+
270
+ // Handle the case for a method with no parameters.
271
+ if ("" .equals (canonicalTypeNameParameters [0 ])) {
272
+ canonicalTypeNameParameters = new String [0 ];
273
+ }
274
+
275
+ // Parse the static type and class.
276
+ tokens = line .substring (parameterEndIndex + 1 ).trim ().split ("\\ s+" );
277
+
278
+ String staticType ;
279
+ String targetJavaClassName ;
280
+
281
+ // Based on the number of tokens, look up the type and class.
282
+ if (tokens .length == 2 ) {
283
+ staticType = tokens [0 ];
284
+ targetJavaClassName = tokens [1 ];
285
+ } else {
286
+ throw new IllegalArgumentException ("invalid static definition: unexpected format [" + line + "]" );
287
+ }
288
+
289
+ // Check the static type is valid.
290
+ if ("bound_to" .equals (staticType ) == false ) {
291
+ throw new IllegalArgumentException (
292
+ "invalid static definition: unexpected static type [" + staticType + "] [" + line + "]" );
293
+ }
294
+
295
+ whitelistBindings .add (new WhitelistBinding (origin , targetJavaClassName ,
296
+ methodName , returnCanonicalTypeName , Arrays .asList (canonicalTypeNameParameters )));
297
+
298
+ // Handle class definition types.
299
+ } else if ("class" .equals (parseType )) {
210
300
// Mark the origin of this parsable object.
211
301
String origin = "[" + filepath + "]:[" + number + "]" ;
212
302
213
303
// Ensure we have a defined class before adding any constructors, methods, augmented methods, or fields.
214
- if (javaClassName == null ) {
215
- throw new IllegalArgumentException ("invalid object definition: expected a class name [" + line + "]" );
304
+ if (parseType == null ) {
305
+ throw new IllegalArgumentException ("invalid definition: expected one of [' class', 'static'] [" + line + "]" );
216
306
}
217
307
218
308
// Handle the case for a constructor definition.
@@ -221,7 +311,7 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
221
311
// Ensure the final token of the line is ')'.
222
312
if (line .endsWith (")" ) == false ) {
223
313
throw new IllegalArgumentException (
224
- "invalid constructor definition: expected a closing parenthesis [" + line + "]" );
314
+ "invalid constructor definition: expected a closing parenthesis [" + line + "]" );
225
315
}
226
316
227
317
// Parse the constructor parameters.
@@ -234,34 +324,34 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
234
324
235
325
whitelistConstructors .add (new WhitelistConstructor (origin , Arrays .asList (tokens )));
236
326
237
- // Handle the case for a method or augmented method definition.
238
- // Expects the following format: ID ID? ID '(' ( ID ( ',' ID )* )? ')' '\n'
327
+ // Handle the case for a method or augmented method definition.
328
+ // Expects the following format: ID ID? ID '(' ( ID ( ',' ID )* )? ')' '\n'
239
329
} else if (line .contains ("(" )) {
240
330
// Ensure the final token of the line is ')'.
241
331
if (line .endsWith (")" ) == false ) {
242
332
throw new IllegalArgumentException (
243
- "invalid method definition: expected a closing parenthesis [" + line + "]" );
333
+ "invalid method definition: expected a closing parenthesis [" + line + "]" );
244
334
}
245
335
246
336
// Parse the tokens prior to the method parameters.
247
337
int parameterIndex = line .indexOf ('(' );
248
- String [] tokens = line .trim (). substring (0 , parameterIndex ).split ("\\ s+" );
338
+ String [] tokens = line .substring (0 , parameterIndex ). trim ( ).split ("\\ s+" );
249
339
250
- String javaMethodName ;
340
+ String methodName ;
251
341
String javaAugmentedClassName ;
252
342
253
343
// Based on the number of tokens, look up the Java method name and if provided the Java augmented class.
254
344
if (tokens .length == 2 ) {
255
- javaMethodName = tokens [1 ];
345
+ methodName = tokens [1 ];
256
346
javaAugmentedClassName = null ;
257
347
} else if (tokens .length == 3 ) {
258
- javaMethodName = tokens [2 ];
348
+ methodName = tokens [2 ];
259
349
javaAugmentedClassName = tokens [1 ];
260
350
} else {
261
351
throw new IllegalArgumentException ("invalid method definition: unexpected format [" + line + "]" );
262
352
}
263
353
264
- String painlessReturnTypeName = tokens [0 ];
354
+ String returnCanonicalTypeName = tokens [0 ];
265
355
266
356
// Parse the method parameters.
267
357
tokens = line .substring (parameterIndex + 1 , line .length () - 1 ).replaceAll ("\\ s+" , "" ).split ("," );
@@ -271,11 +361,11 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
271
361
tokens = new String [0 ];
272
362
}
273
363
274
- whitelistMethods .add (new WhitelistMethod (origin , javaAugmentedClassName , javaMethodName ,
275
- painlessReturnTypeName , Arrays .asList (tokens )));
364
+ whitelistMethods .add (new WhitelistMethod (origin , javaAugmentedClassName , methodName ,
365
+ returnCanonicalTypeName , Arrays .asList (tokens )));
276
366
277
- // Handle the case for a field definition.
278
- // Expects the following format: ID ID '\n'
367
+ // Handle the case for a field definition.
368
+ // Expects the following format: ID ID '\n'
279
369
} else {
280
370
// Parse the field tokens.
281
371
String [] tokens = line .split ("\\ s+" );
@@ -287,20 +377,23 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
287
377
288
378
whitelistFields .add (new WhitelistField (origin , tokens [1 ], tokens [0 ]));
289
379
}
380
+ } else {
381
+ throw new IllegalArgumentException ("invalid definition: unable to parse line [" + line + "]" );
290
382
}
291
383
}
292
384
293
385
// Ensure all classes end with a '}' token before the end of the file.
294
386
if (javaClassName != null ) {
295
- throw new IllegalArgumentException ("invalid class definition: expected closing bracket" );
387
+ throw new IllegalArgumentException ("invalid definition: expected closing bracket" );
296
388
}
297
389
} catch (Exception exception ) {
298
390
throw new RuntimeException ("error in [" + filepath + "] at line [" + number + "]" , exception );
299
391
}
300
392
}
393
+
301
394
ClassLoader loader = AccessController .doPrivileged ((PrivilegedAction <ClassLoader >)resource ::getClassLoader );
302
395
303
- return new Whitelist (loader , whitelistClasses );
396
+ return new Whitelist (loader , whitelistClasses , whitelistBindings );
304
397
}
305
398
306
399
private WhitelistLoader () {}
0 commit comments