2

I've written a cross platform application using SWT. On Mac, it throws a SWTException saying Illegal thread access.

There are many answers which say to use -XstartOnFirstThread

However, that's really inconvenient to use. It's frustrating to have to say

To run the application, simply double click the program, unless you use Mac. If you use Mac, please open up Terminal, and run the following commands. If they do not work please refer to these instructions on how to configure your PATH and JAVA_HOME

Is there any way of fixing this in Java without using -XstartOnFirstThread?

samczsun
  • 1,014
  • 6
  • 16

1 Answers1

1

There's actually a way to programmatically run SWT's readAndDispatch on the main thread without needing to use a command line option. It's not often mentioned in general and mentioned even less when talking about SWT. I just found out about this and it's been a life saver.

com.apple.concurrent.Dispatch exists on Mac only and can produce an Executor which allows submitting tasks onto the main thread. Using this it's possible to create a cross-platform SWT application which always opens on double click.

Of course, because the class doesn't exist on Windows/Linux, you can't simply directly call the methods required. If you do your application will fail on Windows/Linux from ClassNotFoundException. Instead, you'll need to use some reflection to run readAndDispatch on the main thread only if the current OS is Mac.

You'll want to check whether the OS is Mac. To do that you can use the code below.

if (System.getProperty("os.name").toLowerCase().contains("mac"))

After that, you can use reflection to call the methods necessary.

Executor executor;
try {
    Class<?> dispatchClass = Class.forName("com.apple.concurrent.Dispatch");
    Object dispatchInstance = dispatchClass.getMethod("getInstance").invoke(null);
    executor = (Executor) dispatchClass.getMethod("getNonBlockingMainQueueExecutor").invoke(dispatchInstance);
} catch (Throwable throwable) {
    throw new RuntimeException("Could not reflectively access Dispatch", throwable);
}

Finally, you can execute your runnable in the executor, and cry tears of joy because your application is cross-platform again.

samczsun
  • 1,014
  • 6
  • 16
  • 1
    Note: By posting to Stack Overflow you have agreed to license your contribution using [CCA Share Alike](https://creativecommons.org/licenses/by-sa/3.0/) – greg-449 Jan 04 '16 at 16:12