-
-
Save dgageot/bda57296107ca6a0e9df to your computer and use it in GitHub Desktop.
| package test; | |
| import java.lang.reflect.Method; | |
| import java.lang.reflect.Modifier; | |
| import java.util.Arrays; | |
| import java.util.function.Function; | |
| import static java.util.stream.Stream.of; | |
| public class FindParametersTypes { | |
| public static void main(String[] args) { | |
| Function<String, String> inner = new Function<String, String>() { | |
| @Override | |
| public String apply(String s) { | |
| return s; | |
| } | |
| }; | |
| Function<String, String> lambda = s -> s; | |
| of(inner, lambda).forEach(f -> System.out.println(Arrays.toString(firstParameter(f)))); | |
| of(inner, lambda).forEach(f -> System.out.println(Arrays.toString(firstParameterSmart(f)))); | |
| } | |
| private static Class<?>[] firstParameter(Function<String, String> function) { | |
| return function.getClass().getMethods()[0].getParameterTypes(); | |
| } | |
| // Lambda class name: test.Toto$$Lambda$1/1199823423 | |
| // Implementation synthetic method: lambda$main$0 | |
| // | |
| private static Class<?>[] firstParameterSmart(Function<String, String> function) { | |
| String functionClassName = function.getClass().getName(); | |
| int lambdaMarkerIndex = functionClassName.indexOf("$$Lambda$"); | |
| if (lambdaMarkerIndex == -1) { // Not a lambda | |
| return firstParameter(function); | |
| } | |
| String declaringClassName = functionClassName.substring(0, lambdaMarkerIndex); | |
| int lambdaIndex = Integer.parseInt(functionClassName.substring(lambdaMarkerIndex + 9, functionClassName.lastIndexOf('/'))); | |
| Class<?> declaringClass; | |
| try { | |
| declaringClass = Class.forName(declaringClassName); | |
| } catch (ClassNotFoundException e) { | |
| throw new IllegalStateException("Unable to find lambda's parent class " + declaringClassName); | |
| } | |
| for (Method method : declaringClass.getDeclaredMethods()) { | |
| if (method.isSynthetic() | |
| && method.getName().startsWith("lambda$") | |
| && method.getName().endsWith("$" + (lambdaIndex - 1)) | |
| && Modifier.isStatic(method.getModifiers())) { | |
| return method.getParameterTypes(); | |
| } | |
| } | |
| throw new IllegalStateException("Unable to find lambda's implementation method"); | |
| } | |
| } |
seems good. There are many answers, which can solve the problem "how to get parameterized type from a function/predicate",
but when the IDE format/refactor them into a lambda, those answers will not work any more. Because they rely on the method "getGenericInterfaces"
When it is function or predicate or something else, using "getGenericInterfaces" can get a ParameterizedType object and can use getActualTypeArguments of it, but when it comes to lambda, the "getGenericInterfaces" method returns a class rather then a ParameterizedType.
Your gist helps a lot and it can solve the problem.
Thanks for the great example! But I found an exceptional case.
If the lambda for java.util.Function is declared in a Lambda expression, the index between the Lambda object and the method in the root class become different. (My environment is Oracle JDK 1.8.0_171 on MacOS)
public class FindParametersTypes {
public static void main(String[] args) {
Function<String, String> inner = new Function<String, String>() {
@Override
public String apply(String s) {
return s;
}
};
Function<String, String> lambda = s -> s;
Runnable task = () -> {
Function<String, String> lambdaInLambda = s -> s;
of(inner, lambda, lambdaInLambda).forEach(f -> System.out.println(Arrays.toString(firstParameterSmart(f))));
};
task.run();
}In the example above, the name of class of lambdaInLambda is like test.FindParametersTypes$$Lambda$3/1349393271 but the corresponding method in the root class is lambda$null$1 and lambda$null$2 is actually the lambda for forEach so that the firstParameterSmart would cause a misditection.
[class java.lang.String]
[class java.lang.String]
[interface java.util.function.Function]
Although I have not found the solution of the case, just a heads up to you 😃
Tested on Temurin JDK 11 and 17 right now - not working for both static and non-static lambdas.
very good!