How to get lambda expression from Java Method - java

Suppose that I have the following method:
void test () {...}
I am getting this method via reflection, but invoking it will be very slow, so I want to get Runnable from it as if I will write
this::test
Is there any way to achieve this?

I need an implementation for method like this: Runnable toRunnable(Method method); So we are getting a Method and we need to return Runnable
This is not exactly equivalent to this::test, since that also uses the this instance to bind to, so you will also have to pass an instance to bind to. But then you can use method handles, which is the underlying implementation for something like this::test.
With a class like this:
public class MyClass {
public void test() {
System.out.println("Test Called");
}
}
You can create this method:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
public static Runnable toRunnable(Method method, Object instance) throws ReflectiveOperationException {
Lookup lookup = lookup();
MethodHandle test = lookup.unreflect(method);
try {
return (Runnable) LambdaMetafactory.metafactory(
lookup,
"run",
methodType(Runnable.class, instance.getClass()),
methodType(void.class),
test,
methodType(void.class)
).getTarget().invoke(instance);
} catch (Throwable e) {
throw new RuntimeException("Should not occur", e);
}
}
And call it like this:
Object ref = new MyClass(); // get from somewhere
Runnable result = toRunnable(ref.getClass().getMethod("test"), ref);
result.run(); // prints 'Test Called'
The caveat is that the test method has to be accessible from the point at which you're calling lookup(), you can get around this either by passing the Lookup to the method manually, and creating it at a place where you can access the test method. Or if you're in Java 9 you can use privateLookup(Class<?>, Lookup) instead, but the Lookup you pass to that needs to be created in the same module as the method you're trying to access. (in short, method handles has a few more access restrictions to it). But if the method and class you're trying to access are publicly accessible then there's no problem.

Related

How to call functor objects's function without invoking call method

I have a functor object:
private static Func1<MyEvent, Observable<Data>> getDataOnEvent = new Func1<MyEvent, Observable<Data>>() {
#Override
public Observable<Data> call(MyEvent event) {
return ApiFactory.get().getData()
}
};
For its invoking I need to do this:
result = getDataOnEvent.call(someEvent)
Is it possible to do this instead:
result = getDataOnEvent(someEvent)
Like it is done with Python and Javascript? Maybe a new version of java OR some library like Lombok?
Just use,
private static Observable<Data> getDataOnEvent(MyEvent event) {
return ApiFactory.get().getData()
}
and you can call result = getDataOnEvent(someEvent); whenever you need it. As you can see, writing it this way, will save even more boiler code than the five letters .call on the invocation side.
If Func1 is a functional interface, you can use ContainingClass::getDataOnEvent wherever a Func1<MyEvent, Observable<Data>> is expected. You can also store it into a static variable, if you prefer using the simple identifier getDataOnEvent as function:
private static Func1<MyEvent, Observable<Data>> getDataOnEvent
= ContainingClass::getDataOnEvent;
Then you can use getDataOnEvent(event) to call it or getDataOnEvent to refer to it as a Func1 instance whenever you need it.
If Func1 is not a functional interface, then you can’t create the function in this compact form, but on the other hand, in that case it wouldn’t be reasonable to ask for a support for calling an arbitrary method without naming it explicitly, either.
I know what you mean, groovy code call a closure like this:
def code = { 123 };
//can be called like any other method if the variable is a closure.
assert code() == 123;
//can be call explicitly by using `call` method
assert code.call() == 123;
javascript code call a function like this:
let code = () => 123;
//can be called like any other function if the variable is a function.
assert code() == 123;
//can be call explicitly by using `call` method
assert code.call() == 123;
But I can tell you java gammar not support this feature for fields/variables, maybe in the next jdk will be enable this feature which a field/variable refer to Callable.
Fortunately, Single-Static-Import Declarations supports calling a method directly if the static member is a method, for example:
import static java.lang.Math.abs;
assert abs(-1) == 1;
If you really want to make an identifier called like a method call, you can fake something like this:
class ApiFactory {
public static Func1<MyEvent, Observable<Data>> getDataOnEvent = new Func1<MyEvent, Observable<Data>>() {
public Observable<Data> call(MyEvent event) {
return ApiFactory.get().getData();
}
};
public static Observable<Data> getDataOnEvent(MyEvent event) {
return getDataOnEvent.call(event);
}
}
then you can call like this:
import static ${package}.ApiFactory.getDataOnEvent;
// which is calling a static method
result = getDataOnEvent(event);
// which is calling a static field
result = getDataOnEvent.call(event);

EasyMock: andAnswer() vs andDelegateTo()

Which are differences between andAnswer() and andDelegateTo() methods in EasyMock in terms of usage?
First difference
I know that when andAnswer method is used, it is skipped the constructor call. This is important if the constructor makes extra things.
class Dummy {
public Dummy(Object someArgument) {
// some validations of arguments
System.out.println("the constructor is called");
}
public Object method() {
System.out.println("the method is called");
return new Object();
}
}
#Test
public void testSt1() {
Dummy mock = EasyMock.createMock(Dummy.class);
EasyMock.expect(mock.method()).andAnswer(new IAnswer<Object>() {
#Override
public Object answer() throws Throwable {
System.out.println("mocked method is called");
return new Object();
}
} );
EasyMock.replay(mock);
mock.method();
}
#Test
public void testSt2() {
Dummy mock = EasyMock.createMock(Dummy.class);
EasyMock.expect(mock.method()).andDelegateTo(new Dummy(new Dummy(new Object()) {
#Override
public Object method() {
System.out.println("mocked method is called");
return new Object();
}
} );
EasyMock.replay(mock);
mock.method();
}
Results:
testSt1() does not call the constructor of Dummy
testSt2() calls the constructor of Dummy
What are the other differences?
The purpose of the two methods is to provide different levels of responsibility for your tests. Your example isn't that great, though.
Here's a simple method that demonstrates how functionally these two provide different test expectations.
public String foo() throws Exception {
throw new Exception();
}
With andAnswer, you can make a mocked version of this method return a String, even though it would never return one in practice. Your use of andAnswer implies an expected response.
With andDelegateTo, this will always throw an Exception. Your use of andDelegateTo implies an actual response.
andAnswer means your test-specific code will handle the response. For example, if you create a ParrotAnswer for a MockDao update method, the Parrot will return the updated Object, but no Dao is actually instantiated in the process. This is nice for unit testing where you basically walk the test subject through, but doesn't help if your mocked method doesn't do as what you method actually does.
andDelegateTo allows you to provide an actual Object implementing the interface to handle the response. We're allowing our test subject controlled access to a resource, rather than providing unrestricted access to a full resource. benefit of this is that you can test integration into a test environment, but minimize actual changes to the test environment. For example, you can delegate get to a wired Dao to fetch an actual live value from the Db, and mock the delete method, so you don't actually delete that same value during testing (and having to recreate it again later to do the same test if it has a static id, for example).

Not understandable by SpringAop proxies behaviour

I'm not been able to understand by the bold statements:
The key thing to understand here is that the client code inside the
main(..) of the Main class has a reference to the proxy. This means
that method calls on that object reference will be calls on the proxy,
and as such the proxy will be able to delegate to all of the
interceptors (advice) that are relevant to that particular method
call. However, once the call has finally reached the target object,
the SimplePojo reference in this case, any method calls that it may
make on itself, such as this.bar() or this.foo(), are going to be
invoked against the this reference, and not the proxy. This has
important implications. It means that self-invocation is not going to
result in the advice associated with a method invocation getting a
chance to execute.
Code below:
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
public class SimplePojo implements Pojo {
public void foo() {
// this next method invocation is a direct call on the 'this' reference
this.bar();
}
public void bar() {
// some logic...
}
}

Java Class.forName won't compile. Getting "cannot find symbol symbol : method"

I'm trying to use Class.forName and my Intellij is throwing a compile error. My IntelliJ highlights "theResponse" in red (in testMethod) and gives me this error:
cannot find symbol symbol : method
Here is the code (and test) I'm working with...
package http.response;
public class TestClass {
public TestClass() {
PublicRoute publicRoute = new PublicRoute();
}
public String testMethod() throws ClassNotFoundException {
Class c = Class.forName("http.response.PublicRoute");
return c.theResponse("hi");
}
}
package http.response;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class TestClassTest {
#Test
public void test() throws ClassNotFoundException {
TestClass testClass = new TestClass();
assertEquals("public", testClass.testMethod());
}
}
UPDATE: What I was trying to do was "polymorphically" call theResponse from the class that is returned as a String from a HashMap. How would I do this? I'm (loosely) following this example but I didn't understand it fully (http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism). Here is a simplified version of what I'm trying to do. Hopefully that makes sense.
package http.response;
import java.util.HashMap;
public class TestClass {
HashMap map;
public TestClass(HashMap map) {
this.map = map;
}
public String testMethod(String lookupValue) throws ClassNotFoundException {
String className = map.get(lookupValue);
Class c = Class.forName("http.response." + className);
return c.theResponse();
}
}
Class.forName() returns an object of type java.lang.Class. java.lang.Class has no method theResponse, as you can see from its Javadoc.
It sounds like what you actually want to do is construct an instance of the PublicRoute class, and call the method on the instance. But you've already constructed such an instance: it's the publicRoute variable you create in your constructor. Why not just use that object instead?
Edit: Ah, I see what you're trying to do. You basically want a form of the Service Locator pattern.
Create an interface, like so:
public interface ResponseProvider {
String theResponse();
}
Then make all your classes implement that interface:
public class PublicRoute implements ResponseProvider {
#Override
public String theResponse() {
// do whatever
}
}
Then, when you load your Class<?>, you can use the asSubclass() method to turn your Class<?> into a Class<? extends ResponseProvider> -- then newInstance() will give you back a ResponseProvider object that you can call theResponse() on, like so:
String className = ...;
Class<?> klass = Class.forName(className);
Class<? extends ResponseProvider> responseProviderClass
= klass.asSubclass(ResponseProvider.class);
ResponseProvider responseProvider = responseProviderClass.newInstance();
return responseProvider.theResponse();
But don't do that by hand -- instead, use the java.util.ServiceLoader class, which is designed for exactly this purpose. You create a special META-INF/services/com.my.package.ResponseProvider file, with a list of all the possible classes that implement that interface, and then ServiceLoader can give you back instances of each of them.
But... consider not doing that, either. The types of problems that you can solve with the Service Locator pattern are often better solved by using Dependency Injection (see also my answer to another question about Dependency Injection). The Guice DI framework, for example, offers a feature called multibindings which looks like exactly what you need.
If theResponse() belongs to http.response.PublicRoute then it should have been
Class c = Class.forName("http.response.PublicRoute");
return ((PublicRoute) c.newInstance()).theResponse("hi");
But, then there's really no need for Class.forName() as you could use constructor as
return new PublicRoute().theResponse("hi");
The class Class does not have a method named theResponse. From the rest of your code, it doesn't look like you should be using reflection here; you're already referring statically to the PublicRoute class, so there's no point loading it dynamically.
I think you just want to write either this:
return PublicRoute.theResponse("hi");
or this:
return new PublicRoute().theResponse("hi");
(depending whether theResponse is a static method or an instance method).
Let me see if I understand what you're trying to do. You've got a hashmap that will contain a list of classes that you're going to try to call the theResponse(String response) method on, right? I'm assuming you won't know the String that will be put into the hashmap either, right?
Others are right in that you can't just do:
Class c = Class.forName("http.response.PublicRoute");
c.theResponse("hi"); // errors because c has no knowledge of theResponse()
You'll need to cast c to http.response.PublicRoute but then as #Ravi Thapliyal pointed out, you won't need Class.forName anymore! You've got a hashmap of names that could potentially be anything so this won't work.
If I'm understanding you correctly to do what you need, you'll need to use reflection in order to attempt to instance the class then call the method on it.
Here's how you'd do it assuming the theResponse method is a public non-static method and has only 1 parameter.
// Declare the parameter type
Class[] paramString = new Class[1];
paramString[0] = String.class;
String className = map.get(lookupValue);
// Instance the class
Class cls = Class.forName("http.response." + className);
Object obj = cls.newInstance();
// Call the method and pass it the String parameter
method = cls.getDeclaredMethod("theResponse", paramString);
method.invoke(obj, new String("hi"));
Of course you'll need to handle Exceptions but you'd surround the above code with the loop for your hashmap.
I hope this helps!

How do I call a method that has a method as its argument?

Here is a piece of code I have: (what I am trying to do with it is: define a method "renamingrule" in my main class, instantiate a instance of my other class "renamescript" and call its rename method passing as a parameter the "renamingrule" method i've defined in the main class. Everything is well in the RenamScript class, no errors, but i dont know how to call the rename method of the script class from my main class/method. thanks)
public class RenameScript2 {
...
public void rename(Method methodToCall) throws IOException, IllegalAccessException, InvocationTargetException {
try
{
...
String command = "cmd /c rename "+_path+"\\"+"\""+next_file+"\" "
+"\""+methodToCall.invoke(next_file, next_index)+"\"";
p = Runtime.getRuntime().exec(command);
}catch(IOException e1) {} catch(IllegalAccessException IA1) {} catch(InvocationTargetException IT1) {} ;
}//end of rename
} //end of class
//=======================================
public class RenameScriptMain2 {
public static String RenamingRule(String input, int file_row)
{
String output = "renamed file "+(file_row+1)+".mp3";
return output;
}
public static void main(String[] args) throws IOException
{
RenameScript2 renamer = new RenameScript2();
renamer.setPath("c:\\users\\roise\\documents\\netbeansprojects\\temp\\files");
try{
renamer.rename(RenamingRule);
}catch(IOException e2) {};
System.out.println("Done from main()\n\n");
}
} //end of class
You get hold of the Method object through Class.getMethod method. Something like this:
RenameScript2.class.getMethod("rename", parameters);
However, I suggest you consider writing an interface for a class that can perform the renaming, instead of passing a Method.
Such interface could look like
interface RenameAction {
void performRename();
}
To wrap the script in a RenameAction object you would do something like
RenameAction action = new RenameAction() {
void performRename() {
// ...
String command = "cmd /c rename "+_path+"\\"+"\""+next_file+"\" "...
p = Runtime.getRuntime().exec(command);
// ...
}
};
You would then simply do like this:
public void rename(RenameAction action) {
action.performRename();
}
Firstly, aioobe is definitely correct, passing a Method object is a little ugly. I'll assume that you're stuck with it!
To get a method, you'll need to use reflection. The below code grabs the method called toString on the class Integer. It then invokes the toString method.
Method method = Integer.class.getMethod("toString");
Object o = method.invoke(new Integer(7));
System.out.println(o);
Static methods don't need to pass the first parameter to method.invoke
Method method = File.class.getMethod("listRoots");
System.out.println(method.invoke(null));
This shows the reason why you shouldn't use it. That string "toString" and "listRoots" are not refactorable. If someone renames a method, then instead of a compile-time error, you'll get a runtime exception thrown (hence the exceptions you'll need to catch, NoSuchMethodException and IllegalAccessException). It's also much slower to use reflection than to use normal code.
Here is how you should do:
Make class RenameScript2 abstract by adding an abstract method public static String RenamingRule(String input, int file_row)
Then have your main class RenameScriptMain2 extend above class RenameScript2 and provide implementation of the method RenamingRule().
Now inside main method create instance of the class RenameScriptMain2 and call method RenamingRule()

Categories

Resources