Truffleruby: Get an Eclipse SWT example working

Created on 28 Apr 2018  路  7Comments  路  Source: oracle/truffleruby

The goal is to run an Eclipse SWT app with TruffleRuby.

Eclipse SWT can be downloaded from http://download.eclipse.org/eclipse/downloads/ in general and specifically from here: http://download.eclipse.org/eclipse/downloads/drops4/R-4.7.3a-201803300640/#SWT . Unpack the zip file and retrieve swt.jar.

Here is a simple Java app with a window and a button:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.widgets.*;

public class WindowWithButton {
    public static void main(String ...args) {
        Display display = new Display ();
        Shell shell = new Shell(display);
        shell.setSize(320, 240);
        Button button = new Button(shell, SWT.NONE);
        button.setText("Click me, please!");
        button.addSelectionListener(new SelectionListener() {
            @Override
            public void widgetSelected(SelectionEvent selectionEvent) {
                shell.close();
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent selectionEvent) {

            }
        });
        button.pack();
        shell.open ();
        while (!shell.isDisposed ()) {
            if (!display.readAndDispatch ()) display.sleep ();
        }
        display.dispose ();
    }
}

Start it with

java -cp .:swt.jar WindowWithButton

On macOS you need to add a -XstartOnFirstThread argument:

java -XstartOnFirstThread -cp .:swt.jar WindowWithButton

Most helpful comment

Here is a version using the simple Java interop (https://github.com/oracle/truffleruby/blob/master/doc/user/polyglot.md#accessing-java-objects) that works:

display = Java.type('org.eclipse.swt.widgets.Display').new
shell = Java.type('org.eclipse.swt.widgets.Shell').new(display)
shell.setSize(320, 240)
button = Java.type('org.eclipse.swt.widgets.Button').new(shell, Java.type('org.eclipse.swt.SWT')[:NONE])
button.setText("Click me, please!")
listener = Object.new
listener.define_singleton_method(:widgetSelected) { |e| shell.close }
button.addSelectionListener(listener)
button.pack
shell.open
until shell.isDisposed
  display.sleep unless display.readAndDispatch
end
display.dispose
$ jth ruby --jvm.classpath=$PWD/swt.jar truffle-java-interop.rb

All 7 comments

Here is the program converted into Ruby working with JRuby:

java_import org.eclipse.swt.SWT
java_import org.eclipse.swt.widgets.Button
java_import org.eclipse.swt.widgets.Display
java_import org.eclipse.swt.widgets.Shell

display = Display.new
shell = Shell.new(display)
shell.setSize(320, 240)
button = Button.new(shell, SWT::NONE)
button.setText("Click me, please!")
button.addSelectionListener {shell.close}
button.pack
shell.open
until shell.disposed?
  display.sleep unless display.readAndDispatch
end
display.dispose

Run it with

ruby -J-cp swt.jar window_with_button.rb

or on macOS

ruby -J-XstartOnFirstThread -J-cp swt.jar window_with_button.rb

Here is what I am trying to run with TruffleRuby:

display = Java::OrgEclipseSwtWidgets::Display.new
shell = Java::OrgEclipseSwtWidgets::Shell.new(display)
shell.setSize(320, 240)
button = Java::OrgEclipseSwtWidgets::Button.new(shell, Java::OrgEclipseSwt::SWT::NONE)
button.setText("Click me, please!")
button.addSelectionListener {shell.close}
button.pack
shell.open
until shell.disposed?
  display.sleep unless display.readAndDispatch
end
display.dispose

I run it on macOS with

ruby --jvm -J-XstartOnFirstThread -J-cp=swt.jar window_with_button.rb

I get the follow error:

src/window_with_button.rb:1:in `const_missing': uninitialized constant Java::OrgEclipseSwtWidgets (NameError)
        from src/window_with_button.rb:1:in `<main>'

So, I am failing to access the Java package. Maybe a classpath problem?

Thank you for the report.
@aardvark179 should know best about this.

Note that you need to require "java" explicitly to enable JRuby-like Java interop.
With that, both the TruffleRuby and JRuby variants of the script fail similarly by not finding the SWT and Display classes:

$ jth ruby --jvm.classpath=$PWD/swt.jar -rjava truby.rb       
lib/truffle/java/java_utilities.rb:109:in `get_package_or_class': Missing class name ('org.eclipse.swt.widgets.Display') (NameError)
    from lib/truffle/java/java_utilities.rb:87:in `get_relative_package_or_class'
    from lib/truffle/java/java.rb:147:in `method_missing'
    from lib/truffle/java/java.rb:131:in `const_missing'
    from truby.rb:1:in `<main>'

$ jth ruby --jvm.classpath=$PWD/swt.jar -rjava jruby.rb
lib/truffle/java/java_utilities.rb:109:in `get_package_or_class': Missing class name ('org.eclipse.swt.SWT') (NameError)
    from lib/truffle/java/java_utilities.rb:87:in `get_relative_package_or_class'
    from lib/truffle/java/java.rb:147:in `method_missing'
    from jruby.rb:1:in `<main>'

Adding swt.jar on the bootclasspath seems to help, but then I get:

lib/truffle/java/proxy_builder.rb:303:in `combine_with': Clash on alias drag_detect between dragDetect and getDragDetect (NameError)
    from lib/truffle/java/proxy_builder.rb:58:in `add_to_map_internal'
    from lib/truffle/java/proxy_builder.rb:39:in `block in add_to_map'
    from lib/truffle/java/proxy_builder.rb:51:in `alias_names'
    from lib/truffle/java/proxy_builder.rb:38:in `add_to_map'
    from lib/truffle/java/proxy_builder.rb:33:in `add_to_instance'
    from lib/truffle/java/proxy_builder.rb:155:in `block in add_instance_methods'
    from lib/truffle/java/proxy_builder.rb:147:in `each'
    from lib/truffle/java/proxy_builder.rb:147:in `add_instance_methods'
    from lib/truffle/java/proxy_builder.rb:190:in `build'
    from lib/truffle/java/java_utilities.rb:268:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:505:in `make_object_proxy'
    from lib/truffle/java/java_utilities.rb:242:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:505:in `make_object_proxy'
    from lib/truffle/java/java_utilities.rb:242:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:505:in `make_object_proxy'
    from lib/truffle/java/java_utilities.rb:242:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:505:in `make_object_proxy'
    from lib/truffle/java/java_utilities.rb:242:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:505:in `make_object_proxy'
    from lib/truffle/java/java_utilities.rb:242:in `make_proxy'
    from lib/truffle/java/java_utilities.rb:113:in `get_package_or_class'
    from lib/truffle/java/java_utilities.rb:87:in `get_relative_package_or_class'
    from lib/truffle/java/java.rb:147:in `method_missing'
    from lib/truffle/java/java.rb:131:in `const_missing'
    from truby.rb:2:in `<main>'

Here is a version using the simple Java interop (https://github.com/oracle/truffleruby/blob/master/doc/user/polyglot.md#accessing-java-objects) that works:

display = Java.type('org.eclipse.swt.widgets.Display').new
shell = Java.type('org.eclipse.swt.widgets.Shell').new(display)
shell.setSize(320, 240)
button = Java.type('org.eclipse.swt.widgets.Button').new(shell, Java.type('org.eclipse.swt.SWT')[:NONE])
button.setText("Click me, please!")
listener = Object.new
listener.define_singleton_method(:widgetSelected) { |e| shell.close }
button.addSelectionListener(listener)
button.pack
shell.open
until shell.isDisposed
  display.sleep unless display.readAndDispatch
end
display.dispose
$ jth ruby --jvm.classpath=$PWD/swt.jar truffle-java-interop.rb

Okay, we've got two things to resolve here

  1. Which classloaders are we attempting lookups when none is specified.
  2. What is the correct way to handle the mapping of methods which would share a Ruby name? JRuby maps dragDetect and getDragDetect to drag_detect to make their use from Ruby more idiomatic. At the moment we raise an error because we don't know the correct behaviour. I'll go through the JRuby code and attempt to work out a definitive answer to this and add a comment detailing that to this issue.

We currently only support the Truffle-style Java interop with Java.type and not the JRuby-style interop. So I suggest to use the code I posted above and would like to close this issue.

Was this page helpful?
0 / 5 - 0 ratings