Make SWT/JFace support cross-platform, swtjface

Source: Internet
Author: User

Make SWT/JFace support cross-platform, swtjface

Because of the implementation mechanism of SWT, different swt *. jar must be referenced under different platforms. Due to this bottleneck, We need to compile different versions for different platforms. However, this can be avoided. This will be discussed in this article.

I have google three solutions:

1. Use swtjar. jar.

Http://mchr3k.github.io/swtjar/

Its home page has a detailed introduction. But it seems that the download link is no longer working, and a download method is to find the project that references it from github, such as the https://github.com/mchr3k/org.intrace/tree/3a1debcbb831f802219b341fb5e37467b365d443/org.intrace/lib

Swtjar. jar seems to be implemented by replacing the default ClassLoader.

According to my tests, using the swtjar. jar solution, if you reference JFace, you cannot load jface classes successfully. I will discuss the reason later.

 

Http://sourceblogger.googlecode.com/svn/trunk/multiplatform-swt-loader/src/main/java/com/github/jendap/multiplatformswt/loader/MultiPlatformSwtHelper.java 2

I have read the code for this solution, but I have not tried it. It looks complicated, but it seems to have sound functions. If you are interested, you can read it.

 

3, http://stackoverflow.com/questions/2706222/create-cross-platform-java-swt-application

This solution is simple and clear. This article mainly introduces this solution.

 

In fact, the three solutions are essentially the same. We package the swt *. jar of all platforms into the program, and dynamically load the corresponding swt *. jar according to OS and CPU architecture information.

 

Solution 3

The third solution we want to introduce is that in the load class stage, do not load swt *. jar. Instead, it is delayed to the main function execution stage, and then "manually" load the correct swt *. jar according to the OS and CPU architecture.

1) First Add the following method

Private Static VoidLoadSwtJar (){

String swtFileName = "";

Try{

String osName = System.GetProperty("OS. name"). toLowerCase ();

String osArch = System.GetProperty("OS. arch"). toLowerCase ();

FinalClassLoader parentClassLoader = Thread.CurrentThread(). GetContextClassLoader ();

Method addUrlMethod = URLClassLoader.Class. GetDeclaredMethod ("addURL", URL.Class);

AddUrlMethod. setAccessible (True);

 

String swtFileNameOsPart =

OsName. contains ("win ")? "Win32.win32 ":

OsName. contains ("mac ")? "Cocoa. macosx ":

OsName. contains ("linux") | osName. contains ("nix ")? "Gtk. linux ":

""; // Throw new RuntimeException ("Unknown OS name:" + osName)

 

String swtFileNameArchPart = osArch. contains ("64 ")? "X86_64": "x86 ";

SwtFileName = "org. eclipse. swt." + swtFileNameOsPart + "." + swtFileNameArchPart + "-4.4.jar ";

URL swtFileUrl =NewURL ("rsrc:" + swtFileName); // I am using Jar-in-Jar class loader which understands this URL; adjust accordingly if you don't

AddUrlMethod. invoke (parentClassLoader, swtFileUrl );

}

Catch(Exception e ){

System.Out. Println ("Unable to add the swt jar to the class path:" + swtFileName );

E. printStackTrace ();

}

}

 

The function is to manually load the correct swt *. jar File Based on OS and CPU architecture information.

(The above Code may not run correctly in the debugging environment. You need to add a sentence at the beginning:

URL. setURLStreamHandlerFactory (new RsrcURLStreamHandlerFactory (parentClassLoader ));

However, this sentence must be removed when ant compilation is used. Due to the Code Compiled by ant, RsrcURLStreamHandlerFactory has been set to a URL, and repeated settings will cause an exception. I will not go into the details)

 

2) Add a jar-in-jar-loader.jar reference.

Find org. eclipse. jdt. ui _ * version_number * .jarunder eclipse's plugins directory, uncompress it, find jar-in-jar-loader.zip, rename it as a jar-in-jar-loader.jar. Put it in the lib directory of the project and reference it.

The reason for adding this jar is that the loadSwtJar method implicitly uses JarRsrcLoader. class and related classes in it.

 

3) add loadSwtJar () at the beginning of the main function.

 

4) modify the build. xml file.

Yes, you need a build. xml file. If not, use the export jar function of eclipse to generate one. Modify build. the xml file has two main purposes: 1 is to change SWT *. jar is removed from the default load list. 2 is the SWT of all platforms *. jar files are all placed in the package list. One Plus Minus. Here is an example:

<? Xml version = "1.0" encoding = "UTF-8" standalone = "no"?>

<Project default = "create_run_jar" name = "Create Runnable Jar for Project swtguiexample with Jar-in-Jar Loader">

<! -- This file was created by Eclipse Runnable JAR Export Wizard -->

<! -- ANT 1.7 is required

-->

<Target name = "create_run_jar">

<Jar destfile = "/home/binhua/Desktop/bin/swtguiexample. jar">

<Manifest>

<Attribute name = "Main-Class" value = "org. eclipse. jdt. internal. jarinjarloader. JarRsrcLoader"/>

<Attribute name = "Rsrc-Main-Class" value = "swtguiexample. Main"/>

<Attribute name = "Class-Path" value = "."/>

<Attribute name = "Rsrc-Class-Path" value = "./jar-in-jar-loader.jar org. eclipse. equinox. common-3.6.100.v20120522-1841.jar org. eclipse. core. commands-3.6.1.v20120521-2329.jar org. eclipse. osgi-3.8.0.v20120529-1548.jar"/>

</Manifest>

<Zipfileset src = "Library/jar-in-jar-loader.jar"/>

<Fileset dir = "/home/binhua/Desktop/code/swtexample/src/swtguiexample/target/classes"/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/swt/org. eclipse. swt. gtk. linux. x86_64/4.4 "des =" org. eclipse. swt. gtk. linux. x86_64-4.4.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/swt/org. eclipse. swt. gtk. linux. x86/4.4 "primary des =" org. eclipse. swt. gtk. linux. x86-4.4.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/swt/org. eclipse. swt. cocoa. macosx. x86_64/4.4 "des =" org. eclipse. swt. cocoa. macosx. x86_64-4.4.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/swt/org. eclipse. swt. win32.win32. x86_64/4.4 "des =" org. eclipse. swt. win32.win32. x86_64-4.4.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/swt/org. eclipse. swt. win32.win32. x86/4.4 "primary des =" org. eclipse. swt. win32.win32. x86-4.4.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/equinox/org. eclipse. equinox. common/3.6.100.v20120522-1841 "primary des =" org. eclipse. equinox. common-3.6.100.v20120522-1841.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/core/org. eclipse. core. commands/3.6.1.v20120521-2329 "primary des =" org. eclipse. core. commands-3.6.1.v20120521-2329.jar "/>

<Zipfileset dir = "/home/binhua /. m2/repository/org/eclipse/osgi/org. eclipse. osgi/3.8.0.v20120529-1548 "des =" org. eclipse. osgi-3.8.0.v20120529-1548.jar "/>

</Jar>

</Target>

</Project>

Above: 1. In Rsrc <attribute name = "Rsrc-Class-Path", delete SWT *. jar, 2, add SWT for all platforms *. jar to the zipfileset node.

 

5) Well, compile it with ant.

 

Trouble Shooting

The following trouble shooter is actually the key to success:

#1

If JFace *. jar is referenced in the code, ClassNotFoundException will be reported for the above Solution, indicating that a class under JFace cannot be found. This is because JFace fails to load. Why.

Because JFace *. jar is still loaded by default, JFace depends on SWT *. jar, and SWT *. jar has delayed loading. Naturally, JFace *. jar cannot be loaded successfully.

The solution is to delay JFace loading:

1. In Rsrc <attribute name = "Rsrc-Class-Path" of Build. xml, remove JFace *. jar.

2. Add

Private Static VoidLoadSwtJar (){

...

AddUrlMethod. invoke (parentClassLoader, new URL ("rsrc: org. eclipse. jface-3.8.0.v20120521-2329.jar "));

}

 

2 #

If you have the following code:

Public class MyApplicationWindow extends ApplicationWindow implements IExceptionHandler {

...

Public Static VoidMain (String [] args)

{

LoadSwtJar();

...

}

}

ClassNotFoundException will also be reported. Why?

Because ApplicationWindow and IExceptionHandler are both classes in JFace, the main function is placed in MyApplicationWindow. To execute the main function, you must first load ApplicationWindow and IExceptionHandler. At this time, JFace has not been loaded yet, remember, it was delayed.

The solution is simple. Just move the main function away.

 

3 #

If an error occurs in Mac OS X, a parameter must be added:

Java-XstartOnFirstThread-jar *. jar

Well, don't ask me why.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.