Re: RFE: LambdaMetafactory to a class on another ClassLoader - an API gap?

2018-02-16 Thread Geoffrey De Smet

  
  
You're right. I can confirm this works like a charm on JDK 9:

    MethodHandles.Lookup lookup =
  MethodHandles.privateLookupIn(loadedClass,
  MethodHandles.lookup());
      CallSite site = LambdaMetafactory.metafactory(lookup,
      "apply",
      MethodType.methodType(Function.class),
      MethodType.methodType(Object.class,
  Object.class),
      lookup.findVirtual(loadedClass, METHOD_NAME,
  MethodType.methodType(METHOD_RETURN_TYPE)),
      MethodType.methodType(METHOD_RETURN_TYPE,
  loadedClass));
      Function getterFunction = (Function)
  site.getTarget().invokeExact();
Thank you, Claes.


  With kind regards,
Geoffrey De Smet

On 12/02/18 11:37, Claes Redestad
  wrote:


  
  Hi Geoffrey,
  since 9 there's MethodHandles.privateLookup(Class,
Lookup)[1] to get hold of a Lookup with the full, private
capabilities of a specific class, as required by
LambdaMetafactory.
  Replacing line 62 in your sample with the following should
work:
      MethodHandles.Lookup lookup =
MethodHandles.privateLookupIn(loadedClass,
MethodHandles.lookup());
  HTH
  
  /Claes
  
  [1]
  https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.html#privateLookupIn-java.lang.Class-java.lang.invoke.MethodHandles.Lookup-
  
  On 2018-02-12 10:54, Geoffrey De Smet
wrote:
  
  

  

  Hi all,

  
  As a developer for a Java framework, I 'd like to use
the MethodHandle API
  
  or the LambdaMetafactory as an alternative to code
generation or reflection
  
  to call getter/setters on my user's classes, often
loaded by another classloader.
  

Because non-static MethodHandles are currently too slow
  (see the other thread and [1]),

I am forced to use LambdaMetafactory.

However, if the user class is loaded by another
  (non-parent) classloader,

I can't use LambdaMetafactory on it.
  
  The method MethodHandles.lookup(ClassLoader) doesn't
  exist.

Might this be an API gap?




  Proof of code below, which
    throws java.lang.ClassNotFoundException:
junit.framework.TestResult
when calling
    Object returnValue = getterFunction.apply(instance);
  
  
import java.io.File;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.function.Function;

public class LambdaMetafactoryApiGap {

// Proof 1
private static final String JAR_FILE_PATH = System.getProperty("user.home") + "/.m2/repository/junit/junit/4.12/junit-4.12.jar";
private static final String CLASS_TO_LOAD = "junit.framework.TestResult";
private static final String METHOD_NAME = "errorCount";
private static final Class METHOD_RETURN_TYPE = Integer.TYPE;

// Proof 2
//private static final String JAR_FILE_PATH = "/home/ge0ffrey/.m2/repository/org/optaplanner/optaplanner-benchmark/7.5.0.Final/optaplanner-benchmark-7.5.0.Final.jar";
//private static final String CLASS_TO_LOAD = "org.optaplanner.benchmark.impl.result.PlannerBenchmarkResult";
//private static final String METHOD_NAME = "getName";
//private static final Class  METHOD_RETURN_TYPE = String.class;

public static void main(String[] args) throws Throwable {
try {
LambdaMetafactoryApiGap.class.getClassLoader().loadClass(CLASS_TO_LOAD);
System.out.println("The class (" + CLASS_TO_LOAD + ") is already on the normal classpath. Cheater.");
} catch (ClassNotFoundException e) {
// Ok, class is not yet on this normal classpath
}

URL url = "" style="color:rgb(0,0,128);font-weight:bold">new File(JAR_FILE_PATH).toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
Class loadedClass = classLoader.loadClass(CLASS_TO_LOAD);

invokeWithMethodHandle(loadedClass);
invokeWithLambdaMetafactory(loadedClass);
}

private static void invokeWithMethodHandle(Class loadedClass) throws Throwable {
System.out.println("MethodHandle");
System.out.println("");
MethodHandles.Lo

Re: RFE: LambdaMetafactory to a class on another ClassLoader - an API gap?

2018-02-12 Thread Claes Redestad

Hi Geoffrey,

since 9 there's MethodHandles.privateLookup(Class, Lookup)[1] to get 
hold of a Lookup with the full, private capabilities of a specific 
class, as required by LambdaMetafactory.


Replacing line 62 in your sample with the following should work:

    MethodHandles.Lookup lookup = 
MethodHandles.privateLookupIn(loadedClass, MethodHandles.lookup());


HTH

/Claes

[1] 
https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.html#privateLookupIn-java.lang.Class-java.lang.invoke.MethodHandles.Lookup-


On 2018-02-12 10:54, Geoffrey De Smet wrote:

Hi all,

As a developer for a Java framework, I 'd like to use the MethodHandle API
or the LambdaMetafactory as an alternative to code generation or 
reflection
to call getter/setters on my user's classes, often loaded by another 
classloader.


Because non-static MethodHandles are currently too slow (see the other 
thread and [1]),

I am forced to use LambdaMetafactory.
However, if the user class is loaded by another (non-parent) classloader,
I can't use LambdaMetafactory on it.

The method MethodHandles.lookup(ClassLoader) doesn't exist.
Might this be an API gap?

Proof of code below, which
    throws java.lang.ClassNotFoundException: junit.framework.TestResult
when calling
    Object returnValue = getterFunction.apply(instance);

importjava.io.File;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.function.Function;

public class LambdaMetafactoryApiGap {

 // Proof 1 private static final StringJAR_FILE_PATH = 
System.getProperty("user.home") 
+"/.m2/repository/junit/junit/4.12/junit-4.12.jar";
 private static final StringCLASS_TO_LOAD ="junit.framework.TestResult";
 private static final StringMETHOD_NAME ="errorCount";
 private static final ClassMETHOD_RETURN_TYPE = Integer.TYPE;

 // Proof 2 // private static final String JAR_FILE_PATH = 
"/home/ge0ffrey/.m2/repository/org/optaplanner/optaplanner-benchmark/7.5.0.Final/optaplanner-benchmark-7.5.0.Final.jar"; 
// private static final String CLASS_TO_LOAD = 
"org.optaplanner.benchmark.impl.result.PlannerBenchmarkResult"; // 
private static final String METHOD_NAME = "getName"; // private static 
final Class METHOD_RETURN_TYPE = String.class; public static void main(String[] args)throws Throwable {

 try {
 
LambdaMetafactoryApiGap.class.getClassLoader().loadClass(CLASS_TO_LOAD);
 System.out.println("The class (" +CLASS_TO_LOAD +") is already on the 
normal classpath. Cheater.");
 }catch (ClassNotFoundException e) {
 // Ok, class is not yet on this normal classpath }

 URL url =new File(JAR_FILE_PATH).toURI().toURL();
 URLClassLoader classLoader =new URLClassLoader(new URL[]{url});
 Class loadedClass = classLoader.loadClass(CLASS_TO_LOAD);

 invokeWithMethodHandle(loadedClass);
 invokeWithLambdaMetafactory(loadedClass);
 }

 private static void invokeWithMethodHandle(Class loadedClass)throws 
Throwable {
 System.out.println("MethodHandle");
 System.out.println("");
 MethodHandles.Lookup lookup = MethodHandles.lookup();
 MethodHandle methodHandle = lookup
 // Call method signature: public int errorCount() {...} 
.findVirtual(loadedClass,METHOD_NAME, MethodType.methodType(METHOD_RETURN_TYPE))
 // Cast input and output to Object (we can't import the input class in 
this java source) .asType(MethodType.methodType(Object.class, Object.class));


 Object instance = loadedClass.newInstance();
 Object returnValue = methodHandle.invokeExact(instance);
 System.out.println("MethodHandle invoke returns: " + returnValue);
 System.out.println(" but non-static MethodHandles are very slow, so as a framework 
developer I prefer LambdaMetafactory.");

 System.out.println();
 }

 private static void invokeWithLambdaMetafactory(Class 
loadedClass)throws Throwable {
 System.out.println("LambdaMetafactory");
 System.out.println("=");
 // Notice that MethodHandles.lookup(ClassLoader) doesn't exist 
MethodHandles.Lookup lookup = MethodHandles.lookup();
 CallSite site = LambdaMetafactory.metafactory(lookup,
 "apply",
 MethodType.methodType(Function.class),
 MethodType.methodType(Object.class, Object.class),
 lookup.findVirtual(loadedClass,METHOD_NAME, 
MethodType.methodType(METHOD_RETURN_TYPE)),
 MethodType.methodType(METHOD_RETURN_TYPE, loadedClass));
 Function getterFunction = (Function) site.getTarget().invokeExact();

 Object instance = loadedClass.newInstance();
 // Throws java.lang.Cl

RFE: LambdaMetafactory to a class on another ClassLoader - an API gap?

2018-02-12 Thread Geoffrey De Smet
Hi all,

As a developer for a Java framework, I 'd like to use the MethodHandle API
or the LambdaMetafactory as an alternative to code generation or reflection
to call getter/setters on my user's classes, often loaded by another
classloader.

Because non-static MethodHandles are currently too slow (see the other
thread and [1]),
I am forced to use LambdaMetafactory.
However, if the user class is loaded by another (non-parent) classloader,
I can't use LambdaMetafactory on it.

The method MethodHandles.lookup(ClassLoader) doesn't exist.
Might this be an API gap?

Proof of code below, which
throws java.lang.ClassNotFoundException: junit.framework.TestResult
when calling
Object returnValue = getterFunction.apply(instance);

import java.io.File;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.function.Function;

public class LambdaMetafactoryApiGap {

// Proof 1
private static final String JAR_FILE_PATH =
System.getProperty("user.home") +
"/.m2/repository/junit/junit/4.12/junit-4.12.jar";
private static final String CLASS_TO_LOAD = "junit.framework.TestResult";
private static final String METHOD_NAME = "errorCount";
private static final Class METHOD_RETURN_TYPE = Integer.TYPE;

// Proof 2
//private static final String JAR_FILE_PATH =
"/home/ge0ffrey/.m2/repository/org/optaplanner/optaplanner-benchmark/7.5.0.Final/optaplanner-benchmark-7.5.0.Final.jar";
//private static final String CLASS_TO_LOAD =
"org.optaplanner.benchmark.impl.result.PlannerBenchmarkResult";
//private static final String METHOD_NAME = "getName";
//private static final Class  METHOD_RETURN_TYPE = String.class;

public static void main(String[] args) throws Throwable {
try {

LambdaMetafactoryApiGap.class.getClassLoader().loadClass(CLASS_TO_LOAD);
System.out.println("The class (" + CLASS_TO_LOAD + ") is
already on the normal classpath. Cheater.");
} catch (ClassNotFoundException e) {
// Ok, class is not yet on this normal classpath
}

URL url = new File(JAR_FILE_PATH).toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
Class loadedClass = classLoader.loadClass(CLASS_TO_LOAD);

invokeWithMethodHandle(loadedClass);
invokeWithLambdaMetafactory(loadedClass);
}

private static void invokeWithMethodHandle(Class loadedClass)
throws Throwable {
System.out.println("MethodHandle");
System.out.println("");
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle methodHandle = lookup
// Call method signature: public int errorCount() {...}
.findVirtual(loadedClass, METHOD_NAME,
MethodType.methodType(METHOD_RETURN_TYPE))
// Cast input and output to Object (we can't import
the input class in this java source)
.asType(MethodType.methodType(Object.class, Object.class));

Object instance = loadedClass.newInstance();
Object returnValue = methodHandle.invokeExact(instance);
System.out.println("MethodHandle invoke returns: " + returnValue);
System.out.println("  but non-static MethodHandles are very
slow, so as a framework developer I prefer LambdaMetafactory.");
System.out.println();
}

private static void invokeWithLambdaMetafactory(Class
loadedClass) throws Throwable {
System.out.println("LambdaMetafactory");
System.out.println("=");
// Notice that MethodHandles.lookup(ClassLoader) doesn't exist
MethodHandles.Lookup lookup = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
lookup.findVirtual(loadedClass, METHOD_NAME,
MethodType.methodType(METHOD_RETURN_TYPE)),
MethodType.methodType(METHOD_RETURN_TYPE, loadedClass));
Function getterFunction = (Function) site.getTarget().invokeExact();

Object instance = loadedClass.newInstance();
// Throws java.lang.ClassNotFoundException: junit.framework.TestResult
Object returnValue = getterFunction.apply(instance);
System.out.println("LambdaMetafactory invoke returns: " + returnValue);
}

}


[1]
https://www.optaplanner.org/blog/2018/01/09/JavaReflectionButMuchFaster.html

Wkr,
Geoffrey De Smet
___
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev