使用 Javascript 函数接受字节数组,使用 GraalVM 和 Java
Using a Javascript function that accepts a byte array using GraalVM and Java
我有一个Java脚本文件:
https://gist.github.com/VanitySoft/0cfd26991fa9ac33e03782e4316695c2
// lppDecode decodes an array of bytes into an array of ojects,
function lppDecode(bytes) {
//...
}
在我的 Java 测试用例中,我正在尝试发送一个字节数组:
@Test
public void testTestDecorder() throws IOException {
Context context = Context.create();
String javaSctiptDecorder = FileUtils.readFileToString(new File("src/main/resources/decoderOnly.js"));
Value decodeFunction = context.eval("js", javaSctiptDecorder);
byte[] bytes = "016700E1027329EC038807FDD800BEE10000C8".getBytes();
String json = decodeFunction.execute(new String(bytes)).asString();
logger.debug(json);
}
但我一直收到错误消息:
java.lang.UnsupportedOperationException: Unsupported operation Value.execute(Object...) for 'undefined'(language: JavaScript, type: undefined). You can ensure that the operation is supported using Value.canExecute().
at com.oracle.truffle.polyglot.PolyglotEngineException.unsupported(PolyglotEngineException.java:144)
at com.oracle.truffle.polyglot.PolyglotValue.unsupported(PolyglotValue.java:620)
at com.oracle.truffle.polyglot.PolyglotValue.executeUnsupported(PolyglotValue.java:263)
at com.oracle.truffle.polyglot.PolyglotValue$InteropCodeCache$AbstractExecuteNode.executeShared(PolyglotValue.java:1906)
at com.oracle.truffle.polyglot.PolyglotValue$InteropCodeCache$ExecuteNode.executeImpl(PolyglotValue.java:1978)
at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:113)
at com.oracle.truffle.api.impl.DefaultCallTarget.callDirectOrIndirect(DefaultCallTarget.java:84)
at com.oracle.truffle.api.impl.DefaultCallTarget.call(DefaultCallTarget.java:99)
at com.oracle.truffle.api.impl.DefaultRuntimeAccessor$DefaultRuntimeSupport.callProfiled(DefaultRuntimeAccessor.java:119)
at com.oracle.truffle.polyglot.PolyglotValue$InteropValue.execute(PolyglotValue.java:2787)
at org.graalvm.polyglot.Value.execute(Value.java:457)
at com.vanitysoft.nearsight.domain.dao.impl.GraavlTest.testTestDecorder(GraavlTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: Attached Guest Language Frames (1)
如何让 GraalVM 使用这个字节数组?
您的 js 代码似乎缺少括号。我一直在您的代码中按原样拼写变量名中的拼写错误。
@Test
public void testTestDecorder() throws IOException {
Context context = Context.create();
String javaSctiptDecorder = FileUtils.readFileToString(new File("src/main/resources/decoderOnly.js"));
javaSctiptDecorder = "(" + javaSctiptDecorder + ")";
Value decodeFunction = context.eval("js", javaSctiptDecorder);
byte[] bytes = "016700E1027329EC038807FDD800BEE10000C8".getBytes();
String json = decodeFunction .execute(new String(bytes)).asString();
logger.debug(json);
}
周围的括号
问题是在decoderFunction.js you are defining the named function lppDecode
. In Javascript, this is considered a function declaration中,一个语句,而不是一个表达式,Graal 不能计算它。
问题描述在this Github issue. alexjordan's in his answer提供解决方案:
You need to add parentheses around it, otherwise a named function is considered a statement not an expression in JavaScript. (function test() { return 'Hello World' })
should work.
因此,在原始 Java 脚本文件中,或者在构建 Java 变量时,将您的函数括在括号内应该可行,正如 Mythos 在他的回答中所指出的那样。
您可以在浏览器 Java 脚本控制台中检查指示的行为。尝试定义以下内容:
function lppDecode(bytes) { console.log('Bytes:', bytes); return bytes;}
因此,如图所示,浏览器将打印 undefined
:
相反,如果您将函数括在括号中:
(function lppDecode(bytes) { console.log('Bytes:', bytes); return bytes;})
您将收到对该函数的引用:
可以直接使用的:
这就是 Graal 会做的。
这些重要的相关参考资料提供了更多信息:
- Expressions versus statements in JavaScript
- Immediately-Invoked Function Expression (IIFE)
- Javascript: difference between a statement and an expression?
- What is the (function() { } )() construct in JavaScript?
我有一个Java脚本文件: https://gist.github.com/VanitySoft/0cfd26991fa9ac33e03782e4316695c2
// lppDecode decodes an array of bytes into an array of ojects,
function lppDecode(bytes) {
//...
}
在我的 Java 测试用例中,我正在尝试发送一个字节数组:
@Test
public void testTestDecorder() throws IOException {
Context context = Context.create();
String javaSctiptDecorder = FileUtils.readFileToString(new File("src/main/resources/decoderOnly.js"));
Value decodeFunction = context.eval("js", javaSctiptDecorder);
byte[] bytes = "016700E1027329EC038807FDD800BEE10000C8".getBytes();
String json = decodeFunction.execute(new String(bytes)).asString();
logger.debug(json);
}
但我一直收到错误消息:
java.lang.UnsupportedOperationException: Unsupported operation Value.execute(Object...) for 'undefined'(language: JavaScript, type: undefined). You can ensure that the operation is supported using Value.canExecute().
at com.oracle.truffle.polyglot.PolyglotEngineException.unsupported(PolyglotEngineException.java:144)
at com.oracle.truffle.polyglot.PolyglotValue.unsupported(PolyglotValue.java:620)
at com.oracle.truffle.polyglot.PolyglotValue.executeUnsupported(PolyglotValue.java:263)
at com.oracle.truffle.polyglot.PolyglotValue$InteropCodeCache$AbstractExecuteNode.executeShared(PolyglotValue.java:1906)
at com.oracle.truffle.polyglot.PolyglotValue$InteropCodeCache$ExecuteNode.executeImpl(PolyglotValue.java:1978)
at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:113)
at com.oracle.truffle.api.impl.DefaultCallTarget.callDirectOrIndirect(DefaultCallTarget.java:84)
at com.oracle.truffle.api.impl.DefaultCallTarget.call(DefaultCallTarget.java:99)
at com.oracle.truffle.api.impl.DefaultRuntimeAccessor$DefaultRuntimeSupport.callProfiled(DefaultRuntimeAccessor.java:119)
at com.oracle.truffle.polyglot.PolyglotValue$InteropValue.execute(PolyglotValue.java:2787)
at org.graalvm.polyglot.Value.execute(Value.java:457)
at com.vanitysoft.nearsight.domain.dao.impl.GraavlTest.testTestDecorder(GraavlTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: Attached Guest Language Frames (1)
如何让 GraalVM 使用这个字节数组?
您的 js 代码似乎缺少括号。我一直在您的代码中按原样拼写变量名中的拼写错误。
@Test
public void testTestDecorder() throws IOException {
Context context = Context.create();
String javaSctiptDecorder = FileUtils.readFileToString(new File("src/main/resources/decoderOnly.js"));
javaSctiptDecorder = "(" + javaSctiptDecorder + ")";
Value decodeFunction = context.eval("js", javaSctiptDecorder);
byte[] bytes = "016700E1027329EC038807FDD800BEE10000C8".getBytes();
String json = decodeFunction .execute(new String(bytes)).asString();
logger.debug(json);
}
周围的括号
问题是在decoderFunction.js you are defining the named function lppDecode
. In Javascript, this is considered a function declaration中,一个语句,而不是一个表达式,Graal 不能计算它。
问题描述在this Github issue. alexjordan's in his answer提供解决方案:
You need to add parentheses around it, otherwise a named function is considered a statement not an expression in JavaScript.
(function test() { return 'Hello World' })
should work.
因此,在原始 Java 脚本文件中,或者在构建 Java 变量时,将您的函数括在括号内应该可行,正如 Mythos 在他的回答中所指出的那样。
您可以在浏览器 Java 脚本控制台中检查指示的行为。尝试定义以下内容:
function lppDecode(bytes) { console.log('Bytes:', bytes); return bytes;}
因此,如图所示,浏览器将打印 undefined
:
相反,如果您将函数括在括号中:
(function lppDecode(bytes) { console.log('Bytes:', bytes); return bytes;})
您将收到对该函数的引用:
可以直接使用的:
这就是 Graal 会做的。
这些重要的相关参考资料提供了更多信息:
- Expressions versus statements in JavaScript
- Immediately-Invoked Function Expression (IIFE)
- Javascript: difference between a statement and an expression?
- What is the (function() { } )() construct in JavaScript?