BSFPerl

From JVMLanguages


Table of contents

Introduction

BSFPerl is a project that plugs into BSF and provides a bidirectional bridge between Perl and Java. BSFPerl works with any standard Perl installation (5.0 or greater) and requires no Perl code installed. When invoked, BSFPerl will spawn off a Perl process using Runtime.exec(), stream the necessary Perl bootstrap code via the STDIN stream, and then carry out all further communications on the STDIN and STDOUT streams. STDERR is reserved for output coming from the script itself, and from the script's point of view, STDOUT will also be redirected there.

Invoking BSFPerl

BSFPerl currently has no public interface other than a BSFEngine implementation. Future versions may include a separate API so that JSR-223 can also be supported.

You must have a Perl interpreter installed on your local machine and BSFPerl must be able to find it. This means that the path to perl must either by in your PATH environmental variable (or your operating system's equivalent) or you must set the perl.exe Java system property to the fully-qualified path to the Perl executable.

Interacting with Java objects from Perl

All objects passed into Perl from Java will be available as scalars. Objects implementing java.util.Collection will be translated into a reference to an array. Objects implementing java.util.Map will become a reference to a hashtable. All other objects will become a reference blessed into the BSF::JavaObject package, which acts as a proxy into Java. Any method calls will be forwarded on to Java, which will attempt to call a method with the specified name using reflection.

BSFPerl adds a global function to Perl called import that is capable of importing Java packages into Perl. Package names are specified with Perl's standard package separator (::) in place of Java's package separator (.) because . is not a valid character in a Perl identifier. This means that to import the Java class com.oreilly.javalangint.perl.SomeClass you would use:

   import com::oreilly::javalangint::perl::SomeClass;

However, after this point you can refer to SomeClass with any package declaration. There is currently no way to import an entire package.

Once a Java class has been imported, you can call static methods on it. For example:

   import java::lang::Math;

   my $my_sin = Math->sin($my_angle);

You can also instantiate the imported class by calling the new method, which BSFPerl interprets to mean that you want to look for a constructor rather than a static method.

   import java::util::Random;

   my $r = new Random();

   my $n1 = $r->nextDouble;
   my $n2 = $r->nextDouble;
   my $n3 = $r->nextInt;

Since BSFPerl is an ordinary Perl interpreter, everything else should work as expected. In particular, you can use any Perl modules that are installed in your Perl installation.

Interacting with Perl objects from Java

When objects are passed from Perl into Java, BSFPerl does its best to convert the data types in an intuitive way. BSFPerl will only ever try to pass scalar values, however the scalar value in Perl is used to represent numbers (both integer and floating-point), strings, references to arrays, references to maps (hashtables), and references to objects. BSFPerl uses the following rules to distinguish these cases.

  • Is the scalar value a reference to an array? If so, recursively convert the elements of the array and construct a java.util.ArrayList to store the results.
  • Is the scalar value a reference to a hashtable? If so, recursively convert the values of the array and construct a java.util.HashMap where the keys are the keys in Perl (these are always a string) and the values are the converted values.
  • Is the scalar value a reference to a reference? If so, recursively convert the referent and construct an org.sourceforge.bsfperl.PerlReference object containing the converted object.
  • Is the scalar value a reference to an object (i.e., a 'blessed' reference)? If so, construct an org.sourceforge.bsfperl.PerlObject object that can be used (e.g., by BSFEngine.call() to make further method calls.
  • Was the reference used most recently as a number [1] ? If so, use a regular expression to distinguish between floating-point and integer numbers. Construct a java.lang.Double or java.lang.Long as appropriate.
  • Otherwise construct a java.lang.String representing the string.

BSF Support

As of BSFPerl 0.2 and BSF 2.3.1, BSFPerl will be registered automatically (via an included Languages.properties file). If you are using BSFPerl 0.1 or BSF 2.3.0, you will need to register the engine explicitly.

   BSFManager.registerScriptingEngine("bsfperl", "net.sourceforge.bsfperl.PerlEngineImpl", new String[] {"pl"});

Limitations

There is currently no way to access Java fields, either static or instance-based, from Perl. Support for this is planned for a future version.