How to get the MethodInfo of a Java 8 method reference?
Please have a look at the following code:
Method methodInfo = MyClass.class.getMethod("myMethod");
This works, but the method name is passed as a string, so this will compile even if myMethod does not exist.
On the other hand, Java 8 introduces a method reference feature. It is checked at compile time. It is possible to use this feature to get method info?
printMethodName(MyClass::myMethod);
Full example:
@FunctionalInterface
private interface Action {
void invoke();
}
private static class MyClass {
public static void myMethod() {
}
}
private static void printMethodName(Action action) {
}
public static void main(String args) throws NoSuchMethodException {
// This works, but method name is passed as a string, so this will compile
// even if myMethod does not exist
Method methodInfo = MyClass.class.getMethod("myMethod");
// Here we pass reference to a method. It is somehow possible to
// obtain java.lang.reflect.Method for myMethod inside printMethodName?
printMethodName(MyClass::myMethod);
}
In other words I would like to have a code which is the equivalent of the following C# code:
private static class InnerClass
{
public static void MyMethod()
{
Console.WriteLine("Hello");
}
}
static void PrintMethodName(Action action)
{
// Can I get java.lang.reflect.Method in the same way?
MethodInfo methodInfo = action.GetMethodInfo();
}
static void Main()
{
PrintMethodName(InnerClass.MyMethod);
}
java reflection lambda java-8
add a comment |
Please have a look at the following code:
Method methodInfo = MyClass.class.getMethod("myMethod");
This works, but the method name is passed as a string, so this will compile even if myMethod does not exist.
On the other hand, Java 8 introduces a method reference feature. It is checked at compile time. It is possible to use this feature to get method info?
printMethodName(MyClass::myMethod);
Full example:
@FunctionalInterface
private interface Action {
void invoke();
}
private static class MyClass {
public static void myMethod() {
}
}
private static void printMethodName(Action action) {
}
public static void main(String args) throws NoSuchMethodException {
// This works, but method name is passed as a string, so this will compile
// even if myMethod does not exist
Method methodInfo = MyClass.class.getMethod("myMethod");
// Here we pass reference to a method. It is somehow possible to
// obtain java.lang.reflect.Method for myMethod inside printMethodName?
printMethodName(MyClass::myMethod);
}
In other words I would like to have a code which is the equivalent of the following C# code:
private static class InnerClass
{
public static void MyMethod()
{
Console.WriteLine("Hello");
}
}
static void PrintMethodName(Action action)
{
// Can I get java.lang.reflect.Method in the same way?
MethodInfo methodInfo = action.GetMethodInfo();
}
static void Main()
{
PrintMethodName(InnerClass.MyMethod);
}
java reflection lambda java-8
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09
add a comment |
Please have a look at the following code:
Method methodInfo = MyClass.class.getMethod("myMethod");
This works, but the method name is passed as a string, so this will compile even if myMethod does not exist.
On the other hand, Java 8 introduces a method reference feature. It is checked at compile time. It is possible to use this feature to get method info?
printMethodName(MyClass::myMethod);
Full example:
@FunctionalInterface
private interface Action {
void invoke();
}
private static class MyClass {
public static void myMethod() {
}
}
private static void printMethodName(Action action) {
}
public static void main(String args) throws NoSuchMethodException {
// This works, but method name is passed as a string, so this will compile
// even if myMethod does not exist
Method methodInfo = MyClass.class.getMethod("myMethod");
// Here we pass reference to a method. It is somehow possible to
// obtain java.lang.reflect.Method for myMethod inside printMethodName?
printMethodName(MyClass::myMethod);
}
In other words I would like to have a code which is the equivalent of the following C# code:
private static class InnerClass
{
public static void MyMethod()
{
Console.WriteLine("Hello");
}
}
static void PrintMethodName(Action action)
{
// Can I get java.lang.reflect.Method in the same way?
MethodInfo methodInfo = action.GetMethodInfo();
}
static void Main()
{
PrintMethodName(InnerClass.MyMethod);
}
java reflection lambda java-8
Please have a look at the following code:
Method methodInfo = MyClass.class.getMethod("myMethod");
This works, but the method name is passed as a string, so this will compile even if myMethod does not exist.
On the other hand, Java 8 introduces a method reference feature. It is checked at compile time. It is possible to use this feature to get method info?
printMethodName(MyClass::myMethod);
Full example:
@FunctionalInterface
private interface Action {
void invoke();
}
private static class MyClass {
public static void myMethod() {
}
}
private static void printMethodName(Action action) {
}
public static void main(String args) throws NoSuchMethodException {
// This works, but method name is passed as a string, so this will compile
// even if myMethod does not exist
Method methodInfo = MyClass.class.getMethod("myMethod");
// Here we pass reference to a method. It is somehow possible to
// obtain java.lang.reflect.Method for myMethod inside printMethodName?
printMethodName(MyClass::myMethod);
}
In other words I would like to have a code which is the equivalent of the following C# code:
private static class InnerClass
{
public static void MyMethod()
{
Console.WriteLine("Hello");
}
}
static void PrintMethodName(Action action)
{
// Can I get java.lang.reflect.Method in the same way?
MethodInfo methodInfo = action.GetMethodInfo();
}
static void Main()
{
PrintMethodName(InnerClass.MyMethod);
}
java reflection lambda java-8
java reflection lambda java-8
edited Nov 7 '13 at 21:20
Rafal
asked Nov 7 '13 at 19:46
RafalRafal
59341018
59341018
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09
add a comment |
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09
add a comment |
11 Answers
11
active
oldest
votes
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
|
show 4 more comments
Looks like it might be possible after all, by using a proxy to record which method gets called.
https://stackoverflow.com/a/22745127/3478229
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
add a comment |
In my case I was looking for a way to get rid of this in unit tests:
Point p = getAPoint();
assertEquals(p.getX(), 4, "x");
assertEquals(p.getY(), 6, "x");
As you can see someone is testing Method getAPoint and checks that the coordinates are as expected, but in the description of each assert was copied and is not in sync with what is checked. Better would be to write this only once.
From the ideas by @ddan I built a proxy solution using Mockito:
private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) {
final String methodName = getMethodName(object.getClass(), getter);
assertEquals(getter.apply(object), expected, methodName);
}
@SuppressWarnings("unchecked")
private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) {
final Method method = new Method[1];
getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> {
method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod();
})));
return method[0].getName();
}
No I can simply use
assertPropertyEqual(p, Point::getX, 4);
assertPropertyEqual(p, Point::getY, 6);
and the description of the assert is guaranteed to be in sync with the code.
Downside:
- Will be slightly slower than above
- Needs Mockito to work
- Hardly useful to anything but the usecase above.
However it does show a way how it could be done.
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implementString getMethod()in their mocks)
– basin
Aug 30 '18 at 8:54
add a comment |
Though I haven't tried it myself, I think the answer is "no," since a method reference is semantically the same as a lambda.
add a comment |
If you can make the interface Action extend Serializable, then this answer from another question seems to provide a solution (at least on some compilers and runtimes).
add a comment |
We have published the small library de.cronn:reflection-util that can be used to capture a method name.
Example:
class MyClass {
public void myMethod() {
}
}
String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod);
System.out.println(methodName); // prints "myMethod"
Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name.
ClassUtils caches the information such that we do not need to create a new proxy on every invocation.
Please note that this approach doesn’t work with static methods.
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
add a comment |
There may not be a reliable way, but under some circumstances:
- your
MyClassis not final, and has an accessible constructor (limitation of cglib) - your
myMethodis not overloaded, and not static
The you can try using cglib to create a proxy of MyClass, then using an MethodInterceptor to report the Method while the method reference is invoked in a following trial run.
Example code:
public static void main(String args) {
Method m = MethodReferenceUtils.getReferencedMethod(ArrayList.class, ArrayList::contains);
System.out.println(m);
}
You will see the following output:
public boolean java.util.ArrayList.contains(java.lang.Object)
While:
public class MethodReferenceUtils {
@FunctionalInterface
public static interface MethodRefWith1Arg<T, A1> {
void call(T t, A1 a1);
}
public static <T, A1> Method getReferencedMethod(Class<T> clazz, MethodRefWith1Arg<T, A1> methodRef) {
return findReferencedMethod(clazz, t -> methodRef.call(t, null));
}
@SuppressWarnings("unchecked")
private static <T> Method findReferencedMethod(Class<T> clazz, Consumer<T> invoker) {
AtomicReference<Method> ref = new AtomicReference<>();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable {
ref.set(method);
return null;
}
});
try {
invoker.accept((T) enhancer.create());
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
Method method = ref.get();
if (method == null) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
return method;
}
}
In the above code, MethodRefWith1Arg is just a syntax sugar for you to reference an non-static method with one arguments. You can create as many as MethodRefWithXArgs for referencing your other methods.
add a comment |
You can add safety-mirror to your classpath and do like this:
Method m1 = Types.createMethod(Thread::isAlive) // Get final method
Method m2 = Types.createMethod(String::isEmpty); // Get method from final class
Method m3 = Types.createMethod(BufferedReader::readLine); // Get method that throws checked exception
Method m4 = Types.<String, Class>createMethod(getClass()::getDeclaredMethod); //to get vararg method you must specify parameters in generics
Method m5 = Types.<String>createMethod(Class::forName); // to get overloaded method you must specify parameters in generics
Method m6 = Types.createMethod(this::toString); //Works with inherited methods
The library also offers a getName(...) method:
assertEquals("isEmpty", Types.getName(String::isEmpty));
The library is based on Holger's answer: https://stackoverflow.com/a/21879031/6095334
Edit: The library have various shortcomings which I am slowly becoming aware of.
See fx Holger's comment here: How to get the name of the method resulting from a lambda
add a comment |
You can use my library Reflect Without String
Method myMethod = ReflectWithoutString.methodGetter(MyClass.class).getMethod(MyClass::myMethod);
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
add a comment |
So, I play with this code
import sun.reflect.ConstantPool;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class Main {
private Consumer<String> consumer;
Main() {
consumer = this::test;
}
public void test(String val) {
System.out.println("val = " + val);
}
public void run() throws Exception {
ConstantPool oa = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(consumer.getClass());
for (int i = 0; i < oa.getSize(); i++) {
try {
Object v = oa.getMethodAt(i);
if (v instanceof Method) {
System.out.println("index = " + i + ", method = " + v);
}
} catch (Exception e) {
}
}
}
public static void main(String args) throws Exception {
new Main().run();
}
}
output of this code is:
index = 30, method = public void Main.test(java.lang.String)
And as I notice index of referenced method is always 30.
Final code may look like
public Method unreference(Object methodRef) {
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(methodRef.getClass());
try {
Object method = constantPool.getMethodAt(30);
if (method instanceof Method) {
return (Method) method;
}
}catch (Exception ignored) {
}
throw new IllegalArgumentException("Not a method reference.");
}
Be careful with this code in production!
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
add a comment |
Try this
Thread.currentThread().getStackTrace()[2].getMethodName();
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19845213%2fhow-to-get-the-methodinfo-of-a-java-8-method-reference%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
11 Answers
11
active
oldest
votes
11 Answers
11
active
oldest
votes
active
oldest
votes
active
oldest
votes
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
|
show 4 more comments
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
|
show 4 more comments
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.
Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.
Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.
edited Jan 20 '16 at 17:50
answered Nov 7 '13 at 19:55
Mike StrobelMike Strobel
20.7k3655
20.7k3655
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
|
show 4 more comments
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
19
19
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
I am curious if there is any official conversation about this limitation. It seems to me that having type-safe method references would be incredibly valuable in Java. This seems like the perfect time to add them and it would be a shame to see this opportunity to (significantly) improve java's meta-programming be lost.
– Yona Appletree
Jan 20 '14 at 22:32
12
12
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
This is not a limitation; it is simply you are looking for a different feature, method literals. This is a different beast from method references.
– Brian Goetz
May 7 '14 at 3:07
3
3
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
It looks like your answer is incorrect. It's possible, though not straightforward. benjiweber.co.uk/blog/2013/12/28/…
– kd8azz
Apr 25 '15 at 20:04
2
2
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
@BrianGoetz +100 for method literals and while at it property literals. I'm sure your colleagues at the JPA spec team would be internally thankful ;)
– dexter meyers
Jun 22 '15 at 9:58
2
2
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
@Devabc Of course it may be possible in some situations, but there is no supported API that is equivalent to the C# example provided by the OP. I think that is reasonable basis for my answer, and I stand by it. Other possibilities, like using proxies or even analyzing the bootstrap method arguments in the bytecode, are either unreliable or impose additional restrictions. Are they worth mentioning in a separate answer? Sure. Do they make my answer incorrect or worthy of a downvote? I do not see how. That said, I did rephrase my answer to sound less absolute.
– Mike Strobel
Jan 20 '16 at 18:01
|
show 4 more comments
Looks like it might be possible after all, by using a proxy to record which method gets called.
https://stackoverflow.com/a/22745127/3478229
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
add a comment |
Looks like it might be possible after all, by using a proxy to record which method gets called.
https://stackoverflow.com/a/22745127/3478229
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
add a comment |
Looks like it might be possible after all, by using a proxy to record which method gets called.
https://stackoverflow.com/a/22745127/3478229
Looks like it might be possible after all, by using a proxy to record which method gets called.
https://stackoverflow.com/a/22745127/3478229
edited May 23 '17 at 12:10
Community♦
11
11
answered Mar 30 '14 at 14:29
ddanddan
34934
34934
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
add a comment |
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
If you think it is a duplicate, gain enough reputation and flag the question so. Answers are not the right way of handling duplicates.
– lpapp
Mar 30 '14 at 14:46
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
It is possible, but this puts constraints on proxied class. For example, it cannot be final and need to have default public or protected constructor. Moreover this will not work for final methods.
– Rafal
Apr 1 '14 at 6:13
1
1
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
Accepting caveats (we can't distinguish lambdas, and a lambda can contain IFs fooling us), this is a good approach and useful in APIs -- you can grab a ready impl github.com/joj-io/joj-reflect/blob/master/src/main/java/io/joj/… if you wish.
– Piotr Findeisen
Oct 29 '16 at 19:15
add a comment |
In my case I was looking for a way to get rid of this in unit tests:
Point p = getAPoint();
assertEquals(p.getX(), 4, "x");
assertEquals(p.getY(), 6, "x");
As you can see someone is testing Method getAPoint and checks that the coordinates are as expected, but in the description of each assert was copied and is not in sync with what is checked. Better would be to write this only once.
From the ideas by @ddan I built a proxy solution using Mockito:
private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) {
final String methodName = getMethodName(object.getClass(), getter);
assertEquals(getter.apply(object), expected, methodName);
}
@SuppressWarnings("unchecked")
private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) {
final Method method = new Method[1];
getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> {
method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod();
})));
return method[0].getName();
}
No I can simply use
assertPropertyEqual(p, Point::getX, 4);
assertPropertyEqual(p, Point::getY, 6);
and the description of the assert is guaranteed to be in sync with the code.
Downside:
- Will be slightly slower than above
- Needs Mockito to work
- Hardly useful to anything but the usecase above.
However it does show a way how it could be done.
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implementString getMethod()in their mocks)
– basin
Aug 30 '18 at 8:54
add a comment |
In my case I was looking for a way to get rid of this in unit tests:
Point p = getAPoint();
assertEquals(p.getX(), 4, "x");
assertEquals(p.getY(), 6, "x");
As you can see someone is testing Method getAPoint and checks that the coordinates are as expected, but in the description of each assert was copied and is not in sync with what is checked. Better would be to write this only once.
From the ideas by @ddan I built a proxy solution using Mockito:
private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) {
final String methodName = getMethodName(object.getClass(), getter);
assertEquals(getter.apply(object), expected, methodName);
}
@SuppressWarnings("unchecked")
private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) {
final Method method = new Method[1];
getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> {
method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod();
})));
return method[0].getName();
}
No I can simply use
assertPropertyEqual(p, Point::getX, 4);
assertPropertyEqual(p, Point::getY, 6);
and the description of the assert is guaranteed to be in sync with the code.
Downside:
- Will be slightly slower than above
- Needs Mockito to work
- Hardly useful to anything but the usecase above.
However it does show a way how it could be done.
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implementString getMethod()in their mocks)
– basin
Aug 30 '18 at 8:54
add a comment |
In my case I was looking for a way to get rid of this in unit tests:
Point p = getAPoint();
assertEquals(p.getX(), 4, "x");
assertEquals(p.getY(), 6, "x");
As you can see someone is testing Method getAPoint and checks that the coordinates are as expected, but in the description of each assert was copied and is not in sync with what is checked. Better would be to write this only once.
From the ideas by @ddan I built a proxy solution using Mockito:
private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) {
final String methodName = getMethodName(object.getClass(), getter);
assertEquals(getter.apply(object), expected, methodName);
}
@SuppressWarnings("unchecked")
private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) {
final Method method = new Method[1];
getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> {
method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod();
})));
return method[0].getName();
}
No I can simply use
assertPropertyEqual(p, Point::getX, 4);
assertPropertyEqual(p, Point::getY, 6);
and the description of the assert is guaranteed to be in sync with the code.
Downside:
- Will be slightly slower than above
- Needs Mockito to work
- Hardly useful to anything but the usecase above.
However it does show a way how it could be done.
In my case I was looking for a way to get rid of this in unit tests:
Point p = getAPoint();
assertEquals(p.getX(), 4, "x");
assertEquals(p.getY(), 6, "x");
As you can see someone is testing Method getAPoint and checks that the coordinates are as expected, but in the description of each assert was copied and is not in sync with what is checked. Better would be to write this only once.
From the ideas by @ddan I built a proxy solution using Mockito:
private<T> void assertPropertyEqual(final T object, final Function<T, ?> getter, final Object expected) {
final String methodName = getMethodName(object.getClass(), getter);
assertEquals(getter.apply(object), expected, methodName);
}
@SuppressWarnings("unchecked")
private<T> String getMethodName(final Class<?> clazz, final Function<T, ?> getter) {
final Method method = new Method[1];
getter.apply((T)Mockito.mock(clazz, Mockito.withSettings().invocationListeners(methodInvocationReport -> {
method[0] = ((InvocationOnMock) methodInvocationReport.getInvocation()).getMethod();
})));
return method[0].getName();
}
No I can simply use
assertPropertyEqual(p, Point::getX, 4);
assertPropertyEqual(p, Point::getY, 6);
and the description of the assert is guaranteed to be in sync with the code.
Downside:
- Will be slightly slower than above
- Needs Mockito to work
- Hardly useful to anything but the usecase above.
However it does show a way how it could be done.
answered Jun 4 '16 at 14:05
yankeeyankee
20.3k969119
20.3k969119
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implementString getMethod()in their mocks)
– basin
Aug 30 '18 at 8:54
add a comment |
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implementString getMethod()in their mocks)
– basin
Aug 30 '18 at 8:54
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implement
String getMethod() in their mocks)– basin
Aug 30 '18 at 8:54
Thanks, BTW, instead of Mockito we can oblige the developers to extend bean classes themselves (and implement
String getMethod() in their mocks)– basin
Aug 30 '18 at 8:54
add a comment |
Though I haven't tried it myself, I think the answer is "no," since a method reference is semantically the same as a lambda.
add a comment |
Though I haven't tried it myself, I think the answer is "no," since a method reference is semantically the same as a lambda.
add a comment |
Though I haven't tried it myself, I think the answer is "no," since a method reference is semantically the same as a lambda.
Though I haven't tried it myself, I think the answer is "no," since a method reference is semantically the same as a lambda.
answered Nov 7 '13 at 19:51
Matt BallMatt Ball
279k74555629
279k74555629
add a comment |
add a comment |
If you can make the interface Action extend Serializable, then this answer from another question seems to provide a solution (at least on some compilers and runtimes).
add a comment |
If you can make the interface Action extend Serializable, then this answer from another question seems to provide a solution (at least on some compilers and runtimes).
add a comment |
If you can make the interface Action extend Serializable, then this answer from another question seems to provide a solution (at least on some compilers and runtimes).
If you can make the interface Action extend Serializable, then this answer from another question seems to provide a solution (at least on some compilers and runtimes).
edited May 23 '17 at 11:47
Community♦
11
11
answered Apr 18 '15 at 22:14
user102008user102008
20.6k86892
20.6k86892
add a comment |
add a comment |
We have published the small library de.cronn:reflection-util that can be used to capture a method name.
Example:
class MyClass {
public void myMethod() {
}
}
String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod);
System.out.println(methodName); // prints "myMethod"
Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name.
ClassUtils caches the information such that we do not need to create a new proxy on every invocation.
Please note that this approach doesn’t work with static methods.
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
add a comment |
We have published the small library de.cronn:reflection-util that can be used to capture a method name.
Example:
class MyClass {
public void myMethod() {
}
}
String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod);
System.out.println(methodName); // prints "myMethod"
Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name.
ClassUtils caches the information such that we do not need to create a new proxy on every invocation.
Please note that this approach doesn’t work with static methods.
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
add a comment |
We have published the small library de.cronn:reflection-util that can be used to capture a method name.
Example:
class MyClass {
public void myMethod() {
}
}
String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod);
System.out.println(methodName); // prints "myMethod"
Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name.
ClassUtils caches the information such that we do not need to create a new proxy on every invocation.
Please note that this approach doesn’t work with static methods.
We have published the small library de.cronn:reflection-util that can be used to capture a method name.
Example:
class MyClass {
public void myMethod() {
}
}
String methodName = ClassUtils.getVoidMethodName(MyClass.class, MyClass::myMethod);
System.out.println(methodName); // prints "myMethod"
Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name.
ClassUtils caches the information such that we do not need to create a new proxy on every invocation.
Please note that this approach doesn’t work with static methods.
answered Nov 15 '17 at 8:40
Benedikt WaldvogelBenedikt Waldvogel
7,90373749
7,90373749
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
add a comment |
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
Is very limited, not a general solution
– xiaohuo
May 23 '18 at 9:58
add a comment |
There may not be a reliable way, but under some circumstances:
- your
MyClassis not final, and has an accessible constructor (limitation of cglib) - your
myMethodis not overloaded, and not static
The you can try using cglib to create a proxy of MyClass, then using an MethodInterceptor to report the Method while the method reference is invoked in a following trial run.
Example code:
public static void main(String args) {
Method m = MethodReferenceUtils.getReferencedMethod(ArrayList.class, ArrayList::contains);
System.out.println(m);
}
You will see the following output:
public boolean java.util.ArrayList.contains(java.lang.Object)
While:
public class MethodReferenceUtils {
@FunctionalInterface
public static interface MethodRefWith1Arg<T, A1> {
void call(T t, A1 a1);
}
public static <T, A1> Method getReferencedMethod(Class<T> clazz, MethodRefWith1Arg<T, A1> methodRef) {
return findReferencedMethod(clazz, t -> methodRef.call(t, null));
}
@SuppressWarnings("unchecked")
private static <T> Method findReferencedMethod(Class<T> clazz, Consumer<T> invoker) {
AtomicReference<Method> ref = new AtomicReference<>();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable {
ref.set(method);
return null;
}
});
try {
invoker.accept((T) enhancer.create());
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
Method method = ref.get();
if (method == null) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
return method;
}
}
In the above code, MethodRefWith1Arg is just a syntax sugar for you to reference an non-static method with one arguments. You can create as many as MethodRefWithXArgs for referencing your other methods.
add a comment |
There may not be a reliable way, but under some circumstances:
- your
MyClassis not final, and has an accessible constructor (limitation of cglib) - your
myMethodis not overloaded, and not static
The you can try using cglib to create a proxy of MyClass, then using an MethodInterceptor to report the Method while the method reference is invoked in a following trial run.
Example code:
public static void main(String args) {
Method m = MethodReferenceUtils.getReferencedMethod(ArrayList.class, ArrayList::contains);
System.out.println(m);
}
You will see the following output:
public boolean java.util.ArrayList.contains(java.lang.Object)
While:
public class MethodReferenceUtils {
@FunctionalInterface
public static interface MethodRefWith1Arg<T, A1> {
void call(T t, A1 a1);
}
public static <T, A1> Method getReferencedMethod(Class<T> clazz, MethodRefWith1Arg<T, A1> methodRef) {
return findReferencedMethod(clazz, t -> methodRef.call(t, null));
}
@SuppressWarnings("unchecked")
private static <T> Method findReferencedMethod(Class<T> clazz, Consumer<T> invoker) {
AtomicReference<Method> ref = new AtomicReference<>();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable {
ref.set(method);
return null;
}
});
try {
invoker.accept((T) enhancer.create());
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
Method method = ref.get();
if (method == null) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
return method;
}
}
In the above code, MethodRefWith1Arg is just a syntax sugar for you to reference an non-static method with one arguments. You can create as many as MethodRefWithXArgs for referencing your other methods.
add a comment |
There may not be a reliable way, but under some circumstances:
- your
MyClassis not final, and has an accessible constructor (limitation of cglib) - your
myMethodis not overloaded, and not static
The you can try using cglib to create a proxy of MyClass, then using an MethodInterceptor to report the Method while the method reference is invoked in a following trial run.
Example code:
public static void main(String args) {
Method m = MethodReferenceUtils.getReferencedMethod(ArrayList.class, ArrayList::contains);
System.out.println(m);
}
You will see the following output:
public boolean java.util.ArrayList.contains(java.lang.Object)
While:
public class MethodReferenceUtils {
@FunctionalInterface
public static interface MethodRefWith1Arg<T, A1> {
void call(T t, A1 a1);
}
public static <T, A1> Method getReferencedMethod(Class<T> clazz, MethodRefWith1Arg<T, A1> methodRef) {
return findReferencedMethod(clazz, t -> methodRef.call(t, null));
}
@SuppressWarnings("unchecked")
private static <T> Method findReferencedMethod(Class<T> clazz, Consumer<T> invoker) {
AtomicReference<Method> ref = new AtomicReference<>();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable {
ref.set(method);
return null;
}
});
try {
invoker.accept((T) enhancer.create());
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
Method method = ref.get();
if (method == null) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
return method;
}
}
In the above code, MethodRefWith1Arg is just a syntax sugar for you to reference an non-static method with one arguments. You can create as many as MethodRefWithXArgs for referencing your other methods.
There may not be a reliable way, but under some circumstances:
- your
MyClassis not final, and has an accessible constructor (limitation of cglib) - your
myMethodis not overloaded, and not static
The you can try using cglib to create a proxy of MyClass, then using an MethodInterceptor to report the Method while the method reference is invoked in a following trial run.
Example code:
public static void main(String args) {
Method m = MethodReferenceUtils.getReferencedMethod(ArrayList.class, ArrayList::contains);
System.out.println(m);
}
You will see the following output:
public boolean java.util.ArrayList.contains(java.lang.Object)
While:
public class MethodReferenceUtils {
@FunctionalInterface
public static interface MethodRefWith1Arg<T, A1> {
void call(T t, A1 a1);
}
public static <T, A1> Method getReferencedMethod(Class<T> clazz, MethodRefWith1Arg<T, A1> methodRef) {
return findReferencedMethod(clazz, t -> methodRef.call(t, null));
}
@SuppressWarnings("unchecked")
private static <T> Method findReferencedMethod(Class<T> clazz, Consumer<T> invoker) {
AtomicReference<Method> ref = new AtomicReference<>();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable {
ref.set(method);
return null;
}
});
try {
invoker.accept((T) enhancer.create());
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
Method method = ref.get();
if (method == null) {
throw new IllegalArgumentException(String.format("Invalid method reference on class [%s]", clazz));
}
return method;
}
}
In the above code, MethodRefWith1Arg is just a syntax sugar for you to reference an non-static method with one arguments. You can create as many as MethodRefWithXArgs for referencing your other methods.
answered Nov 17 '17 at 5:38
vivimicevivimice
34158
34158
add a comment |
add a comment |
You can add safety-mirror to your classpath and do like this:
Method m1 = Types.createMethod(Thread::isAlive) // Get final method
Method m2 = Types.createMethod(String::isEmpty); // Get method from final class
Method m3 = Types.createMethod(BufferedReader::readLine); // Get method that throws checked exception
Method m4 = Types.<String, Class>createMethod(getClass()::getDeclaredMethod); //to get vararg method you must specify parameters in generics
Method m5 = Types.<String>createMethod(Class::forName); // to get overloaded method you must specify parameters in generics
Method m6 = Types.createMethod(this::toString); //Works with inherited methods
The library also offers a getName(...) method:
assertEquals("isEmpty", Types.getName(String::isEmpty));
The library is based on Holger's answer: https://stackoverflow.com/a/21879031/6095334
Edit: The library have various shortcomings which I am slowly becoming aware of.
See fx Holger's comment here: How to get the name of the method resulting from a lambda
add a comment |
You can add safety-mirror to your classpath and do like this:
Method m1 = Types.createMethod(Thread::isAlive) // Get final method
Method m2 = Types.createMethod(String::isEmpty); // Get method from final class
Method m3 = Types.createMethod(BufferedReader::readLine); // Get method that throws checked exception
Method m4 = Types.<String, Class>createMethod(getClass()::getDeclaredMethod); //to get vararg method you must specify parameters in generics
Method m5 = Types.<String>createMethod(Class::forName); // to get overloaded method you must specify parameters in generics
Method m6 = Types.createMethod(this::toString); //Works with inherited methods
The library also offers a getName(...) method:
assertEquals("isEmpty", Types.getName(String::isEmpty));
The library is based on Holger's answer: https://stackoverflow.com/a/21879031/6095334
Edit: The library have various shortcomings which I am slowly becoming aware of.
See fx Holger's comment here: How to get the name of the method resulting from a lambda
add a comment |
You can add safety-mirror to your classpath and do like this:
Method m1 = Types.createMethod(Thread::isAlive) // Get final method
Method m2 = Types.createMethod(String::isEmpty); // Get method from final class
Method m3 = Types.createMethod(BufferedReader::readLine); // Get method that throws checked exception
Method m4 = Types.<String, Class>createMethod(getClass()::getDeclaredMethod); //to get vararg method you must specify parameters in generics
Method m5 = Types.<String>createMethod(Class::forName); // to get overloaded method you must specify parameters in generics
Method m6 = Types.createMethod(this::toString); //Works with inherited methods
The library also offers a getName(...) method:
assertEquals("isEmpty", Types.getName(String::isEmpty));
The library is based on Holger's answer: https://stackoverflow.com/a/21879031/6095334
Edit: The library have various shortcomings which I am slowly becoming aware of.
See fx Holger's comment here: How to get the name of the method resulting from a lambda
You can add safety-mirror to your classpath and do like this:
Method m1 = Types.createMethod(Thread::isAlive) // Get final method
Method m2 = Types.createMethod(String::isEmpty); // Get method from final class
Method m3 = Types.createMethod(BufferedReader::readLine); // Get method that throws checked exception
Method m4 = Types.<String, Class>createMethod(getClass()::getDeclaredMethod); //to get vararg method you must specify parameters in generics
Method m5 = Types.<String>createMethod(Class::forName); // to get overloaded method you must specify parameters in generics
Method m6 = Types.createMethod(this::toString); //Works with inherited methods
The library also offers a getName(...) method:
assertEquals("isEmpty", Types.getName(String::isEmpty));
The library is based on Holger's answer: https://stackoverflow.com/a/21879031/6095334
Edit: The library have various shortcomings which I am slowly becoming aware of.
See fx Holger's comment here: How to get the name of the method resulting from a lambda
edited Nov 14 '18 at 20:53
answered Nov 13 '18 at 10:29
HervianHervian
681715
681715
add a comment |
add a comment |
You can use my library Reflect Without String
Method myMethod = ReflectWithoutString.methodGetter(MyClass.class).getMethod(MyClass::myMethod);
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
add a comment |
You can use my library Reflect Without String
Method myMethod = ReflectWithoutString.methodGetter(MyClass.class).getMethod(MyClass::myMethod);
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
add a comment |
You can use my library Reflect Without String
Method myMethod = ReflectWithoutString.methodGetter(MyClass.class).getMethod(MyClass::myMethod);
You can use my library Reflect Without String
Method myMethod = ReflectWithoutString.methodGetter(MyClass.class).getMethod(MyClass::myMethod);
answered Apr 24 '18 at 9:33
Dean XuDean Xu
2,0211527
2,0211527
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
add a comment |
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
1
1
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
I've checked. It doesn't work for final methods, nor final classes nor static methods.
– Rafal
Apr 26 '18 at 5:03
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
@Rafal Yes, it is. I had written in the doc. But Your downvote does not make sense . First, your question has no that restriction. I'm going here to give you a solution only for your question. Second, I checked 4 answers above who gives solution and have more than 1 upvote. 3 of them can't work for final/static methods. Third, it's rare to reflect a static method, why you need that?
– Dean Xu
Apr 26 '18 at 5:23
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
I can change downvote, but you have to edit you answer to let me do that (due to Stackoveflow restriction). Upvotes for other questions has been made not by me. My question has no restrictions... yes... so I expect answer which covers all cases or at least it is clear which are not covered.
– Rafal
Apr 27 '18 at 6:30
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
@Rafal Thank you, sir. It doesn't matter. If you see me somewhere else, please don't downvote carelessly :)
– Dean Xu
Apr 27 '18 at 6:34
add a comment |
So, I play with this code
import sun.reflect.ConstantPool;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class Main {
private Consumer<String> consumer;
Main() {
consumer = this::test;
}
public void test(String val) {
System.out.println("val = " + val);
}
public void run() throws Exception {
ConstantPool oa = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(consumer.getClass());
for (int i = 0; i < oa.getSize(); i++) {
try {
Object v = oa.getMethodAt(i);
if (v instanceof Method) {
System.out.println("index = " + i + ", method = " + v);
}
} catch (Exception e) {
}
}
}
public static void main(String args) throws Exception {
new Main().run();
}
}
output of this code is:
index = 30, method = public void Main.test(java.lang.String)
And as I notice index of referenced method is always 30.
Final code may look like
public Method unreference(Object methodRef) {
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(methodRef.getClass());
try {
Object method = constantPool.getMethodAt(30);
if (method instanceof Method) {
return (Method) method;
}
}catch (Exception ignored) {
}
throw new IllegalArgumentException("Not a method reference.");
}
Be careful with this code in production!
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
add a comment |
So, I play with this code
import sun.reflect.ConstantPool;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class Main {
private Consumer<String> consumer;
Main() {
consumer = this::test;
}
public void test(String val) {
System.out.println("val = " + val);
}
public void run() throws Exception {
ConstantPool oa = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(consumer.getClass());
for (int i = 0; i < oa.getSize(); i++) {
try {
Object v = oa.getMethodAt(i);
if (v instanceof Method) {
System.out.println("index = " + i + ", method = " + v);
}
} catch (Exception e) {
}
}
}
public static void main(String args) throws Exception {
new Main().run();
}
}
output of this code is:
index = 30, method = public void Main.test(java.lang.String)
And as I notice index of referenced method is always 30.
Final code may look like
public Method unreference(Object methodRef) {
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(methodRef.getClass());
try {
Object method = constantPool.getMethodAt(30);
if (method instanceof Method) {
return (Method) method;
}
}catch (Exception ignored) {
}
throw new IllegalArgumentException("Not a method reference.");
}
Be careful with this code in production!
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
add a comment |
So, I play with this code
import sun.reflect.ConstantPool;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class Main {
private Consumer<String> consumer;
Main() {
consumer = this::test;
}
public void test(String val) {
System.out.println("val = " + val);
}
public void run() throws Exception {
ConstantPool oa = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(consumer.getClass());
for (int i = 0; i < oa.getSize(); i++) {
try {
Object v = oa.getMethodAt(i);
if (v instanceof Method) {
System.out.println("index = " + i + ", method = " + v);
}
} catch (Exception e) {
}
}
}
public static void main(String args) throws Exception {
new Main().run();
}
}
output of this code is:
index = 30, method = public void Main.test(java.lang.String)
And as I notice index of referenced method is always 30.
Final code may look like
public Method unreference(Object methodRef) {
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(methodRef.getClass());
try {
Object method = constantPool.getMethodAt(30);
if (method instanceof Method) {
return (Method) method;
}
}catch (Exception ignored) {
}
throw new IllegalArgumentException("Not a method reference.");
}
Be careful with this code in production!
So, I play with this code
import sun.reflect.ConstantPool;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class Main {
private Consumer<String> consumer;
Main() {
consumer = this::test;
}
public void test(String val) {
System.out.println("val = " + val);
}
public void run() throws Exception {
ConstantPool oa = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(consumer.getClass());
for (int i = 0; i < oa.getSize(); i++) {
try {
Object v = oa.getMethodAt(i);
if (v instanceof Method) {
System.out.println("index = " + i + ", method = " + v);
}
} catch (Exception e) {
}
}
}
public static void main(String args) throws Exception {
new Main().run();
}
}
output of this code is:
index = 30, method = public void Main.test(java.lang.String)
And as I notice index of referenced method is always 30.
Final code may look like
public Method unreference(Object methodRef) {
ConstantPool constantPool = sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(methodRef.getClass());
try {
Object method = constantPool.getMethodAt(30);
if (method instanceof Method) {
return (Method) method;
}
}catch (Exception ignored) {
}
throw new IllegalArgumentException("Not a method reference.");
}
Be careful with this code in production!
answered Nov 20 '17 at 18:08
Dmitriy V.Dmitriy V.
92
92
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
add a comment |
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
Oh... yes, it is to risky for production ;-)
– Rafal
Apr 26 '18 at 5:04
add a comment |
Try this
Thread.currentThread().getStackTrace()[2].getMethodName();
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
add a comment |
Try this
Thread.currentThread().getStackTrace()[2].getMethodName();
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
add a comment |
Try this
Thread.currentThread().getStackTrace()[2].getMethodName();
Try this
Thread.currentThread().getStackTrace()[2].getMethodName();
answered Jul 26 '17 at 14:55
Asghar NematiAsghar Nemati
326
326
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
add a comment |
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
2
2
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
Please add some words of explanation to your answer. Furthermore, the OP does not want the name of a method currently called but of a method a reference to which is forwarded.
– mkl
Jul 26 '17 at 15:18
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f19845213%2fhow-to-get-the-methodinfo-of-a-java-8-method-reference%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I keep wanting to do this as well. The "Correct" way to do it in most cases would be to create a custom annotation and tag that method via the annotation, but that gets cumbersome pretty fast.
– Bill K
Jun 20 '18 at 22:09