Как вызвать метод 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'
Этот код доступен по следующим ссылкам. Это единственный пример, который мне удалось найти
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