Returns the single abstract method of a class node, if it is a SAM type, or null otherwise. @param type a type for which to search for a single abstract method @return the method node if type is a SAM type, null otherwise
(final ClassNode type)
| 645 | * @return the method node if type is a SAM type, null otherwise |
| 646 | */ |
| 647 | public static MethodNode findSAM(final ClassNode type) { |
| 648 | if (type == null) return null; |
| 649 | if (type.isInterface()) { |
| 650 | MethodNode sam = null; |
| 651 | for (MethodNode mn : type.getAbstractMethods()) { |
| 652 | // ignore methods that will have an implementation |
| 653 | if (Traits.hasDefaultImplementation(mn)) continue; |
| 654 | |
| 655 | final String name = mn.getName(); |
| 656 | if (OBJECT_METHOD_NAME_SET.contains(name)) { |
| 657 | // Avoid unnecessary checking for `Object` methods as possible as we could |
| 658 | if (OBJECT_TYPE.getDeclaredMethod(name, mn.getParameters()) != null) continue; |
| 659 | } |
| 660 | |
| 661 | // we have two methods, so no SAM |
| 662 | if (sam != null) return null; |
| 663 | sam = mn; |
| 664 | } |
| 665 | return sam; |
| 666 | } |
| 667 | if (type.isAbstract()) { |
| 668 | MethodNode sam = null; |
| 669 | for (MethodNode mn : type.getAbstractMethods()) { |
| 670 | if (!hasUsableImplementation(type, mn)) { |
| 671 | if (sam != null) return null; |
| 672 | sam = mn; |
| 673 | } |
| 674 | } |
| 675 | return sam; |
| 676 | } |
| 677 | return null; |
| 678 | } |
| 679 | |
| 680 | private static boolean hasUsableImplementation(final ClassNode c, final MethodNode m) { |
| 681 | ClassNode declaringClass = m.getDeclaringClass(); |
no test coverage detected