@@ -271,9 +271,12 @@ public TypeLiteral<?> getImplementationType() {
271
271
continue ;
272
272
}
273
273
274
- // Skip default methods that java8 may have created.
275
- if (isDefault (method ) && (method .isBridge () || method .isSynthetic ())) {
276
- // Even synthetic default methods need the return type validation...
274
+ // Skip default methods that java8 may have created (or the user specifies to skip).
275
+ if (isDefault (method )
276
+ && (method .isBridge () || method .isSynthetic ()
277
+ || method .isAnnotationPresent (PassthroughDefaultMethods .class )
278
+ || factoryRawType .isAnnotationPresent (PassthroughDefaultMethods .class ))) {
279
+ // Even default methods need the return type validation...
277
280
// unavoidable consequence of javac8. :-(
278
281
validateFactoryReturnType (errors , method .getReturnType (), factoryRawType );
279
282
defaultMethods .put (method .getName (), method );
@@ -388,7 +391,7 @@ public TypeLiteral<?> getImplementationType() {
388
391
warnedAboutUserLookups = true ;
389
392
logger .log (
390
393
Level .WARNING ,
391
- "AssistedInject factory {0} is non-public and has javac-generated default methods. "
394
+ "AssistedInject factory {0} is non-public and has default methods."
392
395
+ " Please pass a `MethodHandles.lookup()` with"
393
396
+ " FactoryModuleBuilder.withLookups when using this factory so that Guice can"
394
397
+ " properly call the default methods. Guice will try to workaround this, but "
@@ -436,6 +439,10 @@ public TypeLiteral<?> getImplementationType() {
436
439
+ " public." ;
437
440
if (handle != null ) {
438
441
methodHandleBuilder .put (defaultMethod , handle );
442
+ } else if (userSpecifiedDefaultMethod (factoryRawType , defaultMethod )) {
443
+ // Don't try to find matching signature for user-specified default methods
444
+ errors .addMessage (failureMsg .get ());
445
+ throw new IllegalStateException ("Can't find method compatible with: " + defaultMethod );
439
446
} else if (!allowMethodHandleWorkaround ) {
440
447
errors .addMessage (failureMsg .get ());
441
448
} else {
@@ -452,8 +459,7 @@ public TypeLiteral<?> getImplementationType() {
452
459
}
453
460
}
454
461
// We always expect to find at least one match, because we only deal with javac-generated
455
- // default methods. If we ever allow user-specified default methods, this will need to
456
- // change.
462
+ // default methods here.
457
463
if (!foundMatch ) {
458
464
throw new IllegalStateException ("Can't find method compatible with: " + defaultMethod );
459
465
}
@@ -473,6 +479,12 @@ public TypeLiteral<?> getImplementationType() {
473
479
}
474
480
}
475
481
482
+ private static boolean userSpecifiedDefaultMethod (Class <?> factoryRawType , Method defaultMethod ) {
483
+ return defaultMethod .isAnnotationPresent (PassthroughDefaultMethods .class )
484
+ || (factoryRawType .isAnnotationPresent (PassthroughDefaultMethods .class )
485
+ && !defaultMethod .isBridge () && !defaultMethod .isSynthetic ());
486
+ }
487
+
476
488
static boolean isDefault (Method method ) {
477
489
// Per the javadoc, default methods are non-abstract, public, non-static.
478
490
// They're also in interfaces, but we can guarantee that already since we only act
0 commit comments