如何从perl6调用Java方法

时间:2014-11-26 18:23:08

标签: jvm jvm-languages perl6 java-interop rakudo

use java::util::zip::CRC32:from<java>;

my $crc = CRC32.new();
for 'Hello, Java'.encode('utf-8') {
    $crc.'method/update/(B)V'($_);
}
say $crc.getValue();
遗憾的是,这不起作用

Method 'method/update/(B)V' not found for invocant of class 'java.util.zip.CRC32'

此代码可从以下链接获得。这是我能找到的唯一例子

  1. Rakudo Perl 6 on the JVM (slides)
  2. Perl 6 Advent Calendar: Day 03 – Rakudo Perl 6 on the JVM

3 个答案:

答案 0 :(得分:7)

最终答案

将下面您的答案清理部分中解释的代码清理与Pepe Schwarz在 Expectation alert 部分中提到的改进结合起来,我们得到:

use java::util::zip::CRC32:from<Java>;

my $crc = CRC32.new();

for 'Hello, Java'.encode('utf-8').list { 
    $crc.update($_);
}

say $crc.getValue();

您的答案已清理

use v6;
use java::util::zip::CRC32:from<Java>;

my $crc = CRC32.new();

for 'Hello, Java'.encode('utf-8').list { # Appended `.list` 
    $crc.'method/update/(I)V'($_); 
}
say $crc.getValue();

一个重要的更改位是附加的.list

'Hello, Java'.encode('utf-8')片段返回一个对象utf8。该对象只返回for语句中的一个值(本身)。所以for只迭代一次,将对象传递给代码块,其中包含update行。

如果update行是.'method/update/([B)V',它会映射到需要8位整数缓冲区的Java方法,那么迭代一次就有意义了,这基本上就是Perl 6 {{1}是的。但是,这需要一些支持Perl 6代码(可能在核心编译器中)来编组(自动转换)Perl 6 utf8到Java utf8,如果该代码曾经存在/工作,那么肯定不是我用最新的Rakudo测试时工作。

但是,如果如上所示添加一个明智的buf[]并更改代码块以匹配,那么事情就会成功。

首先,.list导致.list语句迭代一系列整数。

其次,和你一样,我调用了Java方法的整数arg版本(for)而不是原始缓冲区arg版本,然后代码正常工作。 (这意味着从Perl 6 .'method/update/(I)V'对象返回的无符号8位整数的二进制表示要么已经完全是Java方法所期望的,要么自动为您编组。)

另一个必要的变化是utf8下面的评论需要from<java> - 谢谢。

期望提醒

截至2015年1月:

  • 仅仅使用Rakudo / NQP的JVM后端(即在JVM上运行纯P6代码)仍需要更多强化才能正式宣布准备用于生产。 (这是整个P6生态系统预计将在今年进行的全面强化的补充。)JVM后端有望在2015年实现 - 它有望成为Perl 6首次正式发布的一部分今年的生产使用 - 但这在很大程度上取决于需求,并且有更多的开发人员使用它并提供补丁。

  • 调用Java代码的P6代码是附加项目。 Pepe Schwarz在过去几个月中取得了很大的进步,在学习代码库和landing commits方面取得了进步。他已经实现了在本答案开头显示的明显更好的短名称调用,并完成了更多用于在P6和Java类型之间进行转换的编组逻辑,并且正在积极征求反馈和特定改进请求。

答案 1 :(得分:2)

负责Java互操作这一领域的代码可在类org.perl6.nqp.runtime.BootJavaInterop中找到。它表明重载方法由字符串method/<name>/<descriptor>标识。描述符在函数org.objectweb.asm.Type#getMethodDescriptor中计算。该jar可以通过http://mvnrepository.com/artifact/asm/asm的maven获得。

import java.util.zip.CRC32
import org.objectweb.asm.Type

object MethodSignatures {
  def printSignature(cls: Class[_], method: String, params: Class[_]): Unit = {
    val m = cls.getMethod(method, params)
    val d = Type.getMethodDescriptor(m)
    println(m)
    println(s"\t$d")
  }
  def main(args: Array[String]) {
    val cls = classOf[CRC32]

    # see https://docs.oracle.com/javase/8/docs/api/java/util/zip/CRC32.html
    val ab = classOf[Array[Byte]]
    val i = classOf[Int]

    printSignature(cls, "update", ab)
    printSignature(cls, "update", i)
  }
}

打印

public void java.util.zip.CRC32.update(byte[])
    ([B)V
public void java.util.zip.CRC32.update(int)
    (I)V

因为我想调用这个重载方法的update(int)变体,所以正确的方法调用(在示例程序的第5行)是

$crc.'method/update/(I)V'($_);

这与

崩溃
This representation can not unbox to a native int

最后,由于某些原因我不明白,将同一行更改为

$crc.'method/update/(I)V'($_.Int);

修复了这个问题并且示例运行正常。

代码的最终版本是

use v6;
use java::util::zip::CRC32:from<java>;

my $crc = CRC32.new();

for 'Hello, Java'.encode('utf-8') {
    $crc.'method/update/(I)V'($_.Int);
}
say $crc.getValue();

答案 2 :(得分:1)

我使用Perl 6.c进行了以下修改(2018年1月4日):

use v6;
use java::util::zip::CRC32:from<JavaRuntime>;

my $crc = CRC32.new();

for 'Hello, Java'.encode('utf-8').list { 
    $crc.update($_);
}
say $crc.getValue();

导致:

% perl6-j --version
This is Rakudo version 2017.12-79-g6f36b02 built on JVM
implementing Perl 6.c.

% perl6-j crcjava.p6 
1072431491