Hervian / lambda-factory

A fast alternative to Java Reflection API's method invocation
Apache License 2.0
119 stars 33 forks source link

LambdaConversionException during LambdaFactory Creation in Combination with Reflections #13

Open cobizobi opened 2 years ago

cobizobi commented 2 years ago

Hi, currently I run in a LambdaConversionException when I do the following (class is a Class Object extracted per reflection, not like MyClass.class):

copy = clazz.getDeclaredMethod("method"); lambda_copy = LambdaFactory.create(copy);

The exception is:

java.lang.invoke.LambdaConversionException: Invalid caller: <Original name of the Java Class extracted via reflection>
    at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:125)
    at java.base/java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:175)
    at java.base/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:336)
    at com.github.hervian.lambdas.LambdaFactory.createCallSite(LambdaFactory.java:229)
    at com.github.hervian.lambdas.LambdaFactory.privateCreateLambda(LambdaFactory.java:205)
    at com.github.hervian.lambdas.LambdaFactory.createLambda(LambdaFactory.java:176)
    at com.github.hervian.lambdas.LambdaFactory.create(LambdaFactory.java:171)
    at com.github.hervian.lambdas.LambdaFactory.create(LambdaFactory.java:152)
    at com.github.hervian.lambdas.LambdaFactory.privateCreate(LambdaFactory.java:126)
    at com.github.hervian.lambdas.LambdaFactory.create(LambdaFactory.java:104)

I don't know if this is a bug, so I am also happy about any suggestions on this. Thanks!

hrkalona commented 1 year ago

Which java version are you using? I believe something is broken after java 13. @Hervian can you have a look at this? I am facing the same issue. It seems that they did some change about module checking and the function hasFullPrivilegeAccess returns false

hrkalona commented 1 year ago

On my use case, I was loading an external class with class loader and then I was using LamdaFactory in order to be able to call a static method from the external class, from within my executable. Basically the user could write java code on an external file, then using the compiler tools my app would compile the java code into a class, and the load it and execute.

I found a solution on my problem that worked both in java 8 and up to java 20 without any modifications.

https://stackoverflow.com/questions/50787116/use-lambdametafactory-to-invoke-one-arg-method-on-class-instance-obtained-from-o/50802998#50802998

Basically I do this when using the class loader:

loader = new URLClassLoader(new URL[] {url}) { { byte[] code = gimmeLookupClassDef(); defineClass("GimmeLookup", code, 0, code.length); } };

lookup = (MethodHandles.Lookup) loader.loadClass("GimmeLookup").getField("lookup").get(null);

and GimmeLookup is:

static byte[] gimmeLookupClassDef() { return ( "\u00CA\u00FE\u00BA\u00BE\0\0\0001\0\21\1\0\13GimmeLookup\7\0\1\1\0\20" +"java/lang/Object\7\0\3\1\0\10\1\0\3()V\1\0\4Code\1\0\6lookup\1\0'Ljav" +"a/lang/invoke/MethodHandles$Lookup;\14\0\10\0\11\11\0\2\0\12\1\0)()Ljava/lang" +"/invoke/MethodHandles$Lookup;\1\0\36java/lang/invoke/MethodHandles\7\0\15\14\0" +"\10\0\14\12\0\16\0\17\26\1\0\2\0\4\0\0\0\1\20\31\0\10\0\11\0\0\0\1\20\11\0\5\0" +"\6\0\1\0\7\0\0\0\23\0\3\0\3\0\0\0\7\u00B8\0\20\u00B3\0\13\u00B1\0\0\0\0\0\0" ) .getBytes(StandardCharsets.ISO_8859_1); }

Then I pass this lookup inside the create function of LambdaFactory.

these: MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(method.getDeclaringClass(), MethodHandles.lookup()); or lookup = lookup.in(method.getDeclaringClass());

are no longer needed with that approach.

@Hervian I dont know if you are using a class loader, but it might worth taking a look. If it is the case that this is something else all together, then I apologize for the confusion.