@@ -133,6 +133,7 @@ public final class WhitelistLoader {
133133 */
134134 public static Whitelist loadFromResourceFiles (Class <?> resource , String ... filepaths ) {
135135 List <WhitelistClass > whitelistClasses = new ArrayList <>();
136+ List <WhitelistBinding > whitelistBindings = new ArrayList <>();
136137
137138 // Execute a single pass through the whitelist text files. This will gather all the
138139 // constructors, methods, augmented methods, and fields for each whitelisted class.
@@ -141,8 +142,9 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
141142 int number = -1 ;
142143
143144 try (LineNumberReader reader = new LineNumberReader (
144- new InputStreamReader (resource .getResourceAsStream (filepath ), StandardCharsets .UTF_8 ))) {
145+ new InputStreamReader (resource .getResourceAsStream (filepath ), StandardCharsets .UTF_8 ))) {
145146
147+ String parseType = null ;
146148 String whitelistClassOrigin = null ;
147149 String javaClassName = null ;
148150 boolean noImport = false ;
@@ -165,7 +167,11 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
165167 // Ensure the final token of the line is '{'.
166168 if (line .endsWith ("{" ) == false ) {
167169 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 + "]" );
169175 }
170176
171177 // Parse the Java class name.
@@ -178,41 +184,125 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
178184 throw new IllegalArgumentException ("invalid class definition: failed to parse class name [" + line + "]" );
179185 }
180186
187+ parseType = "class" ;
181188 whitelistClassOrigin = "[" + filepath + "]:[" + number + "]" ;
182189 javaClassName = tokens [0 ];
183190
184191 // Reset all the constructors, methods, and fields to support a new class.
185192 whitelistConstructors = new ArrayList <>();
186193 whitelistMethods = new ArrayList <>();
187194 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+ }
188201
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.
191209 // Expects the following format: '}' '\n'
192210 } 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" );
195213 }
196214
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+ }
199228
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 ;
207231
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 )) {
210300 // Mark the origin of this parsable object.
211301 String origin = "[" + filepath + "]:[" + number + "]" ;
212302
213303 // 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 + "]" );
216306 }
217307
218308 // Handle the case for a constructor definition.
@@ -221,7 +311,7 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
221311 // Ensure the final token of the line is ')'.
222312 if (line .endsWith (")" ) == false ) {
223313 throw new IllegalArgumentException (
224- "invalid constructor definition: expected a closing parenthesis [" + line + "]" );
314+ "invalid constructor definition: expected a closing parenthesis [" + line + "]" );
225315 }
226316
227317 // Parse the constructor parameters.
@@ -234,34 +324,34 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
234324
235325 whitelistConstructors .add (new WhitelistConstructor (origin , Arrays .asList (tokens )));
236326
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'
239329 } else if (line .contains ("(" )) {
240330 // Ensure the final token of the line is ')'.
241331 if (line .endsWith (")" ) == false ) {
242332 throw new IllegalArgumentException (
243- "invalid method definition: expected a closing parenthesis [" + line + "]" );
333+ "invalid method definition: expected a closing parenthesis [" + line + "]" );
244334 }
245335
246336 // Parse the tokens prior to the method parameters.
247337 int parameterIndex = line .indexOf ('(' );
248- String [] tokens = line .trim (). substring (0 , parameterIndex ).split ("\\ s+" );
338+ String [] tokens = line .substring (0 , parameterIndex ). trim ( ).split ("\\ s+" );
249339
250- String javaMethodName ;
340+ String methodName ;
251341 String javaAugmentedClassName ;
252342
253343 // Based on the number of tokens, look up the Java method name and if provided the Java augmented class.
254344 if (tokens .length == 2 ) {
255- javaMethodName = tokens [1 ];
345+ methodName = tokens [1 ];
256346 javaAugmentedClassName = null ;
257347 } else if (tokens .length == 3 ) {
258- javaMethodName = tokens [2 ];
348+ methodName = tokens [2 ];
259349 javaAugmentedClassName = tokens [1 ];
260350 } else {
261351 throw new IllegalArgumentException ("invalid method definition: unexpected format [" + line + "]" );
262352 }
263353
264- String painlessReturnTypeName = tokens [0 ];
354+ String returnCanonicalTypeName = tokens [0 ];
265355
266356 // Parse the method parameters.
267357 tokens = line .substring (parameterIndex + 1 , line .length () - 1 ).replaceAll ("\\ s+" , "" ).split ("," );
@@ -271,11 +361,11 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
271361 tokens = new String [0 ];
272362 }
273363
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 )));
276366
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'
279369 } else {
280370 // Parse the field tokens.
281371 String [] tokens = line .split ("\\ s+" );
@@ -287,20 +377,23 @@ public static Whitelist loadFromResourceFiles(Class<?> resource, String... filep
287377
288378 whitelistFields .add (new WhitelistField (origin , tokens [1 ], tokens [0 ]));
289379 }
380+ } else {
381+ throw new IllegalArgumentException ("invalid definition: unable to parse line [" + line + "]" );
290382 }
291383 }
292384
293385 // Ensure all classes end with a '}' token before the end of the file.
294386 if (javaClassName != null ) {
295- throw new IllegalArgumentException ("invalid class definition: expected closing bracket" );
387+ throw new IllegalArgumentException ("invalid definition: expected closing bracket" );
296388 }
297389 } catch (Exception exception ) {
298390 throw new RuntimeException ("error in [" + filepath + "] at line [" + number + "]" , exception );
299391 }
300392 }
393+
301394 ClassLoader loader = AccessController .doPrivileged ((PrivilegedAction <ClassLoader >)resource ::getClassLoader );
302395
303- return new Whitelist (loader , whitelistClasses );
396+ return new Whitelist (loader , whitelistClasses , whitelistBindings );
304397 }
305398
306399 private WhitelistLoader () {}
0 commit comments