Как вызвать метод Java из perl6

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. Ракудо Perl 6 на JVM (слайды)
  2. Perl 6 Advent Calendar: День 03 - Ракудо Perl 6 на JVM

3 ответа

Решение

Окончательный ответ

Сочетая исправления кода, описанные в приведенном ниже разделе "Очистка вашего ответа ", с улучшениями Пепе Шварца, упомянутыми в разделе предупреждения об ожидании ниже, мы получаем:

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', который сопоставляется с методом Java, который ожидает буфер 8 бит, что, по сути, является Perl 6 utf8 является. Однако для этого потребуется некоторая поддержка кода Perl 6 (предположительно в базовом компиляторе) для маршалирования (автоматического преобразования) Perl 6. utf8 в Java buf[] и если этот код когда-либо существовал / работал, он точно не работает, когда я тестирую с последним Rakudo.

Но если добавить разумный .list как показано выше и изменяет блок кода для соответствия, все работает.

Во-первых, .list результаты в for оператор, повторяющийся по серии целых чисел.

Во-вторых, как и вы, я назвал целочисленную версию аргумента метода Java (.'method/update/(I)V') вместо оригинальной версии буфера arg и код работал правильно. (Это означает, что двоичное представление беззнаковых 8-битных целых, возвращаемых из Perl 6 utf8 Объект либо уже в точности соответствует ожидаемому Java-методу, либо автоматически выполняется для вас.)

Другое необходимое изменение заключается в том, что from<java> должно быть from<Java> за ваш комментарий ниже - спасибо.

Ожидание оповещения

По состоянию на январь 2015 года:

  • Простое использование бэкэнда JVM для Rakudo/NQP (т. Е. Выполнение чистого кода P6 на JVM) по-прежнему требует дополнительной защиты, прежде чем он может быть официально объявлен готовым к использованию. (Это в дополнение к всестороннему укреплению, которое, как ожидается, будет проходить в течение всего года всей экосистеме P6.) Бэкэнд JVM, как мы надеемся, получит его в 2015 году - он, вероятно, станет частью первоначального официального запуска Perl 6, готового к использование производства в этом году - но это будет в значительной степени зависеть от спроса и наличия большего количества разработчиков, использующих его и вносящих исправления.

  • Код P6, вызывающий код Java, является дополнительным проектом. Пепе Шварц за последние пару месяцев добился значительных успехов в ускорении, изучении кодовой базы и совершении посадок. Он уже реализовал явно более приятный вызов короткого имени, показанный в начале этого ответа, и выполнил гораздо больше логики маршалинга для преобразования между типами P6 и Java и активно запрашивает отзывы и запросы на конкретные улучшения.

Код, который отвечает за эту область взаимодействия Java, находится в классе org.perl6.nqp.runtime.BootJavaInterop, Предполагается, что перегруженные методы идентифицируются строкой method/<name>/<descriptor>, Дескриптор вычисляется в функции org.objectweb.asm.Type#getMethodDescriptor, Этот jar доступен через maven с http://mvnrepository.com/artifact/asm/asm.

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();

Я получил это, чтобы работать на Perl 6.c со следующей модификацией (4 января 2018 года):

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
Другие вопросы по тегам