Java 7 - MethodHandles - invokeExact() and bindTo() - java

Two questions regarding the MethodHandle class:
Is it true that every call to invokeExact() requires type casting of the return value (except for target methods that return void or Object) ?
It seems that a MethodHandle can only be bound once to a receiver. Given an arbitrary MethodHandle instance, is there any way to determine whether it has already been bound and if so, to what type?
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle handle = lookup.bind(new Object(), "toString", MethodType.methodType(String.class));
String s = (String) handle.invokeExact();
System.out.println(s);
try {
handle.invokeExact();
}
catch (WrongMethodTypeException e) {
System.out.println(e);
}
try {
handle.bindTo(new Object());
}
catch (IllegalArgumentException e) {
System.out.println(e);
}
}

You can call bindTo multiple times, but you should not. The implementation assumes you want to set the receiver, if you start using this to also set arguments you produce a more complicated handle, that is more difficult to compile into lambda forms and then potentially less efficient. I advise using MethodHandles#insertArguments instead

Related

Helper method that returns a thing, or causes a return in the calling scope / context

I can't figure out how to factor out this code.
private CompletionStage<Response<String>> foo(RequestContext rc) {
final Optional<String> campaignIdOpt = rc.request().parameter("campaignId").filter(s -> !s.isEmpty());
final Optional<String> creativeIdOpt = rc.request().parameter("creativeId").filter(s -> !s.isEmpty());
Optional<Uuid> campaignIdOptOfUuid = Optional.empty();
if (campaignIdOpt.isPresent()) {
try {
campaignIdOptOfUuid = Optional.of(UuidUtils.fromString(campaignIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid campaignId: %s", campaignIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid campaignId provided.")));
}
}
Optional<Uuid> creativeIdOptOfUuid = Optional.empty();
if (creativeIdOpt.isPresent()) {
try {
creativeIdOptOfUuid = Optional.of(UuidUtils.fromString(creativeIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid creativeId: %s", creativeIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid creativeId provided.")));
}
}
// Simplified, do something with Uuids.
return bar(campaignIdOptOfUuid, creativeIdOptOfUuid);
}
Basically, we very frequently need to parse Google protobuf Uuids from a query string to pass on to another service that will find (or not find). We need to pass along an empty optional if a parameter was not set or an empty string, as both cases mean, "Don't filter by this parameter." Finally, if the string doesn't parse at all, then we want to immediately return an error 400 (Bad Request), rather than pass along a non-sense param to the service.
So, codewise, I want a utility method that
takes an Optional<String>, and
returns an Optional<Uuid> if present, Optional.empty() otherwise, and
if an exception is thrown, return an error from the original context.
But obviously, I can't "double-return." What pattern do I use to achieve this though? I tried to create an encapsulator for both an Optional<Uuid> and a CompletionStage<Response<String>> but it was awkward. Is there some idiomatic way of doing this?
You can use a loop. A loop allows you to handle all elements equally, thus removing the code duplication, while still allowing to return immediately:
private CompletionStage<Response<String>> foo(RequestContext rc) {
String[] parameters = {"campaignId", "creativeId" };
List<Optional<Uuid>> uuids = new ArrayList<>(parameters.length);
for(String param: parameters) {
Optional<String> o1 = rc.request().parameter(param).filter(s -> !s.isEmpty());
Optional<Uuid> o2;
try {
o2 = o1.map(UuidUtils::fromString);
} catch(IllegalArgumentException e) {
LOG.error(String.format("Invalid %s: %s", param, o1.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST
.withReasonPhrase("Invalid "+param+ " provided.")));
}
uuids.add(o2);
}
// Simplified, do something with Uuids.
return bar(uuids.get(0), uuids.get(1));
}
Otherwise, you would need to create a method returning an object holding two alternative results (like Either); the JDK does not provide such a type yet. A method could simply throw on an erroneous condition but that would bring you back to square one when the common code is mostly the exception handling.
Note that calling Optional.map on an empty optional will already return an empty optional, without evaluating the provided function, so you don’t need to check via ifPresent, etc.

Wrong number of arguments on method.invoke

I currently have this code:
public class Pants {
public static void main(String[] args) {
Pants pants = new Pants();
pants.eat(10, 10.3, "Nice.");
Object[] params = {(long)10, 10.3, "Nice."};
Method eatMethod = pants.getClass().getMethods()[0];
try
{
eatMethod.invoke(pants, params);
} catch (IllegalAccessException | InvocationTargetException e)
{
e.printStackTrace();
}
}
public void eat(long amount, double size, String name) {
System.out.println("You ate");
}
}
It always throws
IllegalArgumentException: wrong number of arguments.
This happened with other methods too. I used the same parameters in eat() as in method.invoke, and the types are the same. The error is thrown on
eatMethod.invoke(pants, params);
As the comments say. We don't know wich method is pants.getClass().getMethods()[0]. Try to get the name with eatMethod.getName() and see if is really the method eat. If
not you can try with this.
java.lang.reflect.Method method;
method = pants.getClass().getMethod("eat", Long.class, Double.class, String.class);
.
.
.
method.invoke(pants,params );
Also... Checking the Java Docs The methods are never sorted
The elements in the returned array are not sorted and are not in any
particular order.
So sometimes your code might work and sometimes not.
It turns out that when I used getMethods()[0], I was getting the main method and calling that, which obviously has no parameters so it didn't work. Ideally I should've used
getMethod("eat", long.class, double.class, String.class)
which does work.

Use java lambda expressions

I'm beginning with Java 8 and I was wondering if I can convert a loop with a try-catch clause, into a lambda function?
Below is the method code I would like to convert into:
for (File f: files) {
JSONOject obj;
try (FileWriter fw= new FileWriter("path.csv")) {
obj= (JSONObject) parser.parse(new FileWriter(f));
readOBJ(valueType,results,obj);
results.put(day, new JobClass(day,work, time,description));
Date d= results.keySet();
Calendar c= Calendar.getinstance();
c.setTime(d);
Map<Date, JobClass> daysList= new HashMap<>();
j.insertDaysList(results,c,fw,daysList);
results.putAll(daysList);
j.resSort(results,resDayList);
} catch (IOException ex) {
e.printStacktrace();
}
}
return resDaysList;
Assuming it's the files iteration you want to convert to a Stream, that can easily be done. At the moment, your loop contents don't even throw uncaught exceptions, so there's no difficulty here (though I would suggest refactoring it into its own method first).
As lambda expressions in Java are just a means to conveniently provide implementations of single-abstract-method (SAM) interfaces as anonymous objects and the standard Stream interface offers the forEach() method for internal iteration, you can encapsulate pretty much everything you want to within your expression.
forEach(Consumer<? super T> action) expects you to provide it with an object of the Consumer interface, which need only have one method implementation consuming an object of any kind and returning no value.
So you simply put the code within your loop into the expression (or, as already proposed, transfer it into it's own method first) and you're done. The only thing you'll need to think about is how to treat your return statement, as it's not possible to return values from within the forEach() method (due to it being a so called "terminal" method of return type void). But you'll be able to pass your list into the lambda expression, modify your values in any way you see fit and keep working with it after the lambda is done, without any problem.
The try-catch-block does not affect the lambda expression itself. After all, the following two segments of code are equivalent:
List<String> someList = Arrays.asList("example", "of", "lambda", "code");
// lambda style
someList.stream().forEach( item -> {
try {
System.out.println(item.toString());
} catch (Exception e) {
e.printStackTrace();
}
});
// anonymous object style
someList.stream().forEach(new Consumer<String>() {
#Override
public void accept(String s) {
try {
System.out.println(item.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});

Variable method reference in java 8

I am trying to create a method reference with the variable, which holds method name for some method from an object:
SomeClass obj = new SomeClass();
String methodName = "someMethod";
I am looking for way to create exactly obj::someMethod, but using variable methodName for this. Is it possible?
I know how to create functional interface instance from methodName and obj:
() -> {
try {
return obj.getClass().getMethod(methodName).invoke(obj);
} catch (NoSuchMethodException | IllegalAccessException e) {
return null;
}
};
but I am wondering is this can be done in more shorthand way.
If you strive for brevity rather than performance, there are Expression and Statement since Java 1.4.
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
try {
Object result=new Expression(obj, methodName, arg).getValue();
new Statement(System.out, "println", new Object[]{ result }).execute();
} catch (Exception ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
}
But if you want to use them in the context of the standard function interfaces, which don’t allow checked exceptions, the exception handling will dominate the source code.
You can bind a reflectively acquired method to a functional interface even under Java 7:
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
MethodHandle mh=MethodHandles.insertArguments(
MethodHandles.lookup().bind(obj, methodName,
MethodType.methodType(String.class, int.class, int.class)),
0, arg);
s = MethodHandleProxies.asInterfaceInstance(Supplier.class, mh);
mh=MethodHandles.lookup().bind(System.out, "println",
MethodType.methodType(void.class, String.class));
c = MethodHandleProxies.asInterfaceInstance(Consumer.class, mh);
} catch(NoSuchMethodException | IllegalAccessException ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
This is not shorter, but avoids performing the reflective lookup in each function evaluation.
Potentially more efficient is to use the LambdaMetafactory introduced in Java 8, which is the back-end of the lambda expressions and method references at runtime.
Object obj="example";
String methodName="substring";
Object[] arg={ 2, 5 };
Supplier<String> s;
Consumer<String> c;
try {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh=lookup.findVirtual(String.class, methodName,
MethodType.methodType(String.class, int.class, int.class));
s = (Supplier<String>)LambdaMetafactory.metafactory(lookup, "get",
mh.type().changeReturnType(Supplier.class),
MethodType.methodType(Object.class), mh, MethodType.methodType(String.class))
.getTarget().bindTo(obj).invokeWithArguments(arg);
mh=MethodHandles.lookup().findVirtual(PrintStream.class, "println",
MethodType.methodType(void.class, String.class));
c = (Consumer<String>)LambdaMetafactory.metafactory(lookup, "accept",
MethodType.methodType(Consumer.class, PrintStream.class),
MethodType.methodType(void.class, Object.class), mh,
MethodType.methodType(void.class, String.class))
.getTarget().bindTo(System.out).invokeExact();
} catch(Throwable ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return;
}
String result=s.get();
c.accept(result);
This has a higher creation complexity, but the subsequent execution of the functions will have an efficiency on par with compile-time method references as there is no technical difference anymore.
This is a very rare case - it's highly unlikely that the Java8 syntax sugar has been optimised for this. In particular, it would be impossible for the usual compile-time type checking to occur (remember that a method reference is just syntax sugar for an anonymous class that adheres to a particular type contract).
If this pattern is common in your codebase (hopefully it's not!), you could just move it to, say, a static utility method, and then do () -> Utils.invoke(obj, methodName).

Calling a java method with array of testcases

First, I know the Title is a bit ambiguous. Actually I don't know how to write it better!
Second, I will describe the problem.
Situation:
I am practicing on an online judge (OJ), so in case of wrong output, the OJ shows me the test case which makes my code to fail. Normally, I can copy my code and paste it into Eclipse, then call my function with that test case and debug my code.
But the problem when the test case is a multiple calls for my function (Like testing an enhanced version of a priority queue), let's assume there were n calls till the fail of the code. So to debug the code, I will have to call the function say n times! Which is not logical!
Function the OJ will call:
public void enqueue (int value)
{
// implementation
}
public int dequeue ()
{
// implementation
}
Test case makes the code to fail:
Last executed input: enqueue(5, 3), enqueue(51, 60), enqueue(0, 14), enqueue(364, 16),... dequeue(),...
Action:
I need a way to call the function with an array of test cases in order to be able to debug the code.
OR
By some way call the function with its parameter directly from the string. Something like invoke("enqueue(5, 3)");
After some investigation, I found a way to do the Action I need by using Java Reflection Also a helpful thread What is reflection and why is it useful?
I managed to develop a tool, here you are the steps:
Copy the test case in a String
Split the string on each function call
Remove the function name from each call, and store them in array of String in order.
Split the parameter
Now I have 2 arrays of integers for param1 and param2, and an array of String for invokations
I used Reflection in order to be able to call the methods from a string of calls, inside a for loop.
Then we have this
public class Test
{
public static void main(String[] args)
{
String testCase = "enqueue(5, 3), enqueue(51, 60), enqueue(0, 14), enqueue(364, 16), dequeue()";
// Prepare parameters and invocations
int[] param1; // assuming it is ready
int[] param2; // assuming it is ready
String[] calls; // assuming it is ready
try
{
Class calledClass = Class.forName("OJ.Prob3");
Method calledMethod1 = calledClass.getDeclaredMethod("enqueue", String.class, int.class);
Method calledMethod2 = calledClass.getDeclaredMethod("dequeue", null);
for (int i = 0 ; i < calls.length ; i++)
{
if (calls[i].equalsIgnoreCase("enqueue"))
calledMethod1.invoke(calledClass.newInstance(), param[i], param2[i]);
else if (calls[i].equalsIgnoreCase("dequeue"))
calledMethod2.invoke(calledClass.newInstance())
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (NoSuchMethodException e)
{
e.printStackTrace();
} catch (SecurityException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (IllegalArgumentException e)
{
e.printStackTrace();
} catch (InvocationTargetException e)
{
e.printStackTrace();
}
}
}
I already tested this solution and it works really very smooth, but please if anyone has a better solution, you will be more than welcome.
I will finalize the code and make it something like a tool, and I will post it soon, in order to make everybody's life easier debugging the online judges test cases.
Update:
You can do the same for the static methods, just remove .newInstance() from calledMethod1.invoke(calledClass.newInstance(), param[i], param2[i]); to something like calledMethod1.invoke(calledClass, param[i], param2[i]);

Categories

Resources