19
19
import com .beust .jcommander .JCommander ;
20
20
import com .beust .jcommander .Parameter ;
21
21
import com .beust .jcommander .ParameterException ;
22
+ import com .google .auto .value .AutoOneOf ;
22
23
import com .google .cloud .functions .BackgroundFunction ;
23
24
import com .google .cloud .functions .HttpFunction ;
24
25
import com .google .cloud .functions .RawBackgroundFunction ;
@@ -250,34 +251,48 @@ public void startServer() throws Exception {
250
251
servletContextHandler .setContextPath ("/" );
251
252
server .setHandler (NotFoundHandler .forServlet (servletContextHandler ));
252
253
253
- Optional < Class <?>> functionClass = loadFunctionClass ();
254
+ ClassOrException functionClass = loadFunctionClass ();
254
255
255
256
HttpServlet servlet ;
256
257
if ("http" .equals (functionSignatureType )) {
257
- if (functionClass .isPresent ()) {
258
- servlet = NewHttpFunctionExecutor .forClass (functionClass .get ());
259
- } else {
260
- FunctionLoader <HttpCloudFunction > loader = new FunctionLoader <>(
261
- functionTarget , functionClassLoader , new HttpFunctionSignatureMatcher ());
262
- HttpCloudFunction function = loader .loadUserFunction ();
263
- servlet = new HttpFunctionExecutor (function );
258
+ switch (functionClass .getKind ()) {
259
+ case LOADED_CLASS :
260
+ servlet = NewHttpFunctionExecutor .forClass (functionClass .loadedClass ());
261
+ break ;
262
+ default :
263
+ FunctionLoader <HttpCloudFunction > loader =
264
+ new FunctionLoader <>(
265
+ functionTarget ,
266
+ functionClassLoader ,
267
+ new HttpFunctionSignatureMatcher (),
268
+ functionClass .exception ());
269
+ HttpCloudFunction function = loader .loadUserFunction ();
270
+ servlet = new HttpFunctionExecutor (function );
264
271
}
265
272
} else if ("event" .equals (functionSignatureType )) {
266
- if (functionClass .isPresent ()) {
267
- servlet = NewBackgroundFunctionExecutor .forClass (functionClass .get ());
268
- } else {
269
- FunctionLoader <BackgroundCloudFunction > loader =
270
- new FunctionLoader <>(
271
- functionTarget , functionClassLoader , new BackgroundFunctionSignatureMatcher ());
272
- BackgroundCloudFunction function = loader .loadUserFunction ();
273
- servlet = new BackgroundFunctionExecutor (function );
273
+ switch (functionClass .getKind ()) {
274
+ case LOADED_CLASS :
275
+ servlet = NewBackgroundFunctionExecutor .forClass (functionClass .loadedClass ());
276
+ break ;
277
+ default :
278
+ FunctionLoader <BackgroundCloudFunction > loader =
279
+ new FunctionLoader <>(
280
+ functionTarget ,
281
+ functionClassLoader ,
282
+ new BackgroundFunctionSignatureMatcher (),
283
+ functionClass .exception ());
284
+ BackgroundCloudFunction function = loader .loadUserFunction ();
285
+ servlet = new BackgroundFunctionExecutor (function );
274
286
}
275
287
} else if (functionSignatureType == null ) {
276
- if (functionClass .isPresent ()) {
277
- servlet = servletForDeducedSignatureType (functionClass .get ());
278
- } else {
279
- throw new RuntimeException (
280
- "Class " + functionTarget + " does not exist or could not be loaded" );
288
+ switch (functionClass .getKind ()) {
289
+ case LOADED_CLASS :
290
+ servlet = servletForDeducedSignatureType (functionClass .loadedClass ());
291
+ break ;
292
+ default :
293
+ throw new RuntimeException (
294
+ "Class " + functionTarget + " does not exist or could not be loaded" ,
295
+ functionClass .exception ());
281
296
}
282
297
} else {
283
298
String error = String .format (
@@ -294,18 +309,44 @@ public void startServer() throws Exception {
294
309
server .join ();
295
310
}
296
311
297
- private Optional <Class <?>> loadFunctionClass () {
312
+ @ AutoOneOf (ClassOrException .Kind .class )
313
+ abstract static class ClassOrException {
314
+ enum Kind {LOADED_CLASS , EXCEPTION }
315
+
316
+ abstract Kind getKind ();
317
+
318
+ abstract Class <?> loadedClass ();
319
+
320
+ abstract ClassNotFoundException exception ();
321
+
322
+ static ClassOrException of (Class <?> c ) {
323
+ return AutoOneOf_Invoker_ClassOrException .loadedClass (c );
324
+ }
325
+
326
+ static ClassOrException of (ClassNotFoundException e ) {
327
+ return AutoOneOf_Invoker_ClassOrException .exception (e );
328
+ }
329
+ }
330
+
331
+ private ClassOrException loadFunctionClass () {
298
332
String target = functionTarget ;
333
+ ClassNotFoundException firstException = null ;
299
334
while (true ) {
300
335
try {
301
- return Optional .of (functionClassLoader .loadClass (target ));
336
+ return ClassOrException .of (functionClassLoader .loadClass (target ));
302
337
} catch (ClassNotFoundException e ) {
338
+ if (firstException == null ) {
339
+ firstException = e ;
340
+ }
303
341
// This might be a nested class like com.example.Foo.Bar. That will actually appear as
304
342
// com.example.Foo$Bar as far as Class.forName is concerned. So we try to replace every dot
305
343
// from the last to the first with a $ in the hope of finding a class we can load.
306
344
int lastDot = target .lastIndexOf ('.' );
307
345
if (lastDot < 0 ) {
308
- return Optional .empty ();
346
+ // We're going to try to load the function target using the old form, classname.method.
347
+ // But it's at least as likely that the class does exist, but we failed to load it for
348
+ // some other reason. So ensure that we keep the exception to show to the user.
349
+ return ClassOrException .of (firstException );
309
350
}
310
351
target = target .substring (0 , lastDot ) + '$' + target .substring (lastDot + 1 );
311
352
}
0 commit comments