JDK-8015236 : Provide Class.isFuntionalInterface functionality in core reflection
Type:Enhancement
Component:core-libs
Sub-Component:java.lang:reflect
Affected Version:8
Priority:P4
Status:Open
Resolution:Unresolved
OS:generic
CPU:generic
Submitted:2013-05-22
Updated:2015-02-03
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.
It would be helpful if core reflection included at least an approximation to a Class.isFuntionalInterface predicate.
Comments
Plan is to defer for 8, possibly take up again in the future.
20-09-2013
Since this idea was proposed, there have been some significant changes: i) the VM (and, by extension, reflection) no longer knows or cares about the language-level concept of overriding (where descriptors are different due to generics or covariant overriding); ii) the LambdaMetafactory no longer knows or cares about interfaces with a single method.
As a result, there is not longer a clear-cut definition of "functional interface" for the reflection library, nor is there a definitive use case in the standard API (i.e., what can I do with this thing if isFunctionalInterface returns true?)
It is reasonable that clients of the LambdaMetafactory might still want to reflectively identify a descriptor(s) to implement, and there is some non-trivial logic involved. But it's not clear exactly what the reflection API should do to help this process.
Examples of alternatives:
--
Alternative 1 (no API change):
Class<?> c = ...;
List<Method> abs = Arrays.stream(c.getMethods())
.filter(m -> Modifier.isAbstract(m.getModifiers()))
.filter(m -> /* complicated logic to match object methods */) // if desired
.collect(something);
// excuse my ignorance of streams
if (c.isInterface() && abs.length == 1) // call metafactory
else // error
--
Alternative 2 (no API change):
Class<?> c = ...;
if (c.isAnnotationPresent(FunctionalInterface.class)) {
List<Method> abs = Arrays.stream(c.getMethods())
.filter(m -> Modifier.isAbstract(m.getModifiers()))
.filter(m -> /* complicated logic to match object methods */) // mandatory
.collect(something);
// excuse my ignorance of streams
// call metafactory with all methods
}
else // error
--
Alternative 3 (isFunctionalInterface, getFunctionalInterfaceMethod):
Class<?> c = ...;
if (c.isFunctionalInterface()) {
Method m = c.getFunctionalInterfaceMethod();
// call metafactory
}
else // error
--
Alternative 4 (getAbstractMethods):
Class<?> c = ...;
if (c.isInterface()) {
Method[] abs = c.getAbstractMethods(); // automatically filters interfaces' object methods
if (c.isAnnotationPresent(FunctionalInterface.class)) // call metafactory with all methods (optional)
else if (abs.length == 1) // call metafactory
else // error
}
else // error
--
I kind of like the general-purpose utility of the last one. If someone wants to implement a class/interface by _any_ means, they need to know its abstract methods, and so 'getAbstractMethods' would nicely fill a hole there.
19-09-2013
This method, if it exists, is likely related to the valid inputs to the LambdaMetafactory. We need to sort out the corner-case behaviors there before we know what a class-level view of "functional interface" looks like.