It is difficult to find any clues for the topic. All I could find is questions about converting one functional interface to another and some articles on type casting in Java. Not what I was looking for.
This question is about converting lambda → Method
and I want the opposite, to convert Method
to any functional interface, for example, to Consumer
.
The way I found is to create a lambda adapter around the Method#invoke
method:
public void registerCallbacks(final Object annotated) {
Class clazz = annotated.getClass();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Callback.class)) {
Callback registration = method.getAnnotation(Callback.class);
List<String> warnings = new ArrayList<>(3);
if (!Modifier.isPublic(method.getModifiers()))
warnings.add(String.format("Method %s must be public", method));
if (method.getParameterCount() != 1)
warnings.add(String.format("Method %s must consume only one argument", method));
if (method.getParameterCount() == 1 && !method.getParameterTypes()[0].equals(Integer.class))
warnings.add(String.format("Method %s must consume %s", method, Integer.class));
if (!warnings.isEmpty()) {
warnings.forEach(log::warn);
continue;
}
CALLBACKS_MAPPER.registerCallback((param) -> {
try {
method.invoke(annotated, param);
} catch (IllegalAccessException | InvocationTargetException e) {
// Should not happen due to checks before.
log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
}
});
log.info("Registered {} as a callback", method);
}
}
}
However I want to avoid writing
CALLBACKS_MAPPER.registerCallback((param) -> {
try {
method.invoke(annotated, param);
} catch (IllegalAccessException | InvocationTargetException e) {
// Should not happen due to checks before.
log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
}
});
in favor of something simpler, like
CALLBACKS_MAPPER.registerCallback(SomeApacheLib.methodToFunction(annotated, method));
➥ So, is there a way to map old Java 1.1 reflection library to newer Java 8 functional interfaces, or it is me being stupid and the abovementioned solution with lambda is fine as it is?
If you're content with using reflection under the hood, just don't like the
try
/catch
around theinvoke
, you can just make a simple utility function like:And that gives you exactly the syntax you wanted:
But if you want to actually avoid reflection altogether, you can use
LambdaMetafactory
to create aConsumer
:Change
String
to whatever your callbacks are expected to accept. And then:Of course, the only proper solution here is that you refactor your code to use a known callback interface on which you can normally call a defined method, instead of passing
Method
s around.