jvmrakurakudojava-interop

How do I invoke a Java method from 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();

sadly, this does not work

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

This code is available at the following links. It is the only example I've been able to find

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

Solution

  • Final answer

    Combining the code cleanups explained in the Your answer cleaned up section below with Pepe Schwarz's improvements mentioned in the Expectation alert section below we get:

    use java::util::zip::CRC32:from<Java>;
    
    my $crc = CRC32.new();
    
    for 'Hello, Java'.encode('utf-8').list { 
        $crc.update($_);
    }
    
    say $crc.getValue();
    

    Your answer cleaned up

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

    One important changed bit is the appended .list.

    The 'Hello, Java'.encode('utf-8') fragment returns an object, a utf8. That object returns just one value (itself) to the for statement. So the for iterates just once, passing the object to the code block with the update line in it.

    Iterating just once could make sense if the update line was .'method/update/([B)V', which maps to a Java method that expects a buffer of 8 bit ints, which is essentially what a Perl 6 utf8 is. However, that would require some support Perl 6 code (presumably in the core compiler) to marshal (automagically convert) the Perl 6 utf8 into a Java buf[] and if that code ever existed/worked it sure isn't working when I test with the latest Rakudo.

    But if one appends a judicious .list as shown above and changes the code block to match, things work out.

    First, the .list results in the for statement iterating over a series of integers.

    Second, like you, I called the Integer arg version of the Java method (.'method/update/(I)V') instead of the original buffer arg version and the code then worked correctly. (This means that the binary representation of the unsigned 8 bit integers returned from the Perl 6 utf8 object is either already exactly what the Java method expects or is automagically marshaled for you.)

    Another required change is that the from<java> needs to be from<Java> per your comment below -- thanks.

    Expectation alert

    As of Jan 2015: