When developing an Eclipse RCP application in the past, you needed to use the Standard Widget Toolkit (SWT) as UI toolkit for creating and rendering the user interface. With Eclipse 4 you are not restricted to SWT anymore. The architecture separated the application model and the rendering, which allows to create an Eclipse based application using a different UI toolkit. Currently there are implementations for JavaFX and Vaadin available.
The following recipe shows the steps necessary to migrate a simple Eclipse 4 application from SWT to JavaFX using the e(fx)clipse tooling and runtime. It is based on the basic recipe introduced in a previous blog post and can also be used as basis for further recipes.
Cookware
- JDK 8
- e(fx)clipse IDE 1.2.0
- JavaFX tooling and runtime for Eclipse and OSGi
- http://efxclipse.bestsolution.at/install.html#all-in-one
- Ensure the IDE is started with Java 8 if you have multiple Java versions installed
- After starting the IDE and choosing a workspace, update the IDE to ensure the latest service release is installed. This is necessary to get the latest bugfixes and security patches.
- Main Menu → Help → Check for Updates
Ingredients
This recipe uses the Eclipse RCP Cookbook – Basic Recipe. To get started fast with this recipe, we have prepared the basic recipe for you on GitHub.
If you want to use the prepared basic recipe to follow the migration from SWT to JavaFX, import the project by cloning the Git repository:
- File → Import → Git → Projects from Git
- Click Next
- Select Clone URI
- Enter URI https://github.com/fipro78/e4-cookbook-basic-recipe.git
- Click Next
- Select the master branch
- Click Next
- Choose a directory where you want to store the checked out sources
- Click Next
- Select Import existing projects
- Click Next
- Click Finish
Preparation
Step 1: Update the Target Platform
- Open the target definition de.codecentric.eclipse.tutorial.target.target in the project de.codecentric.eclipse.tutorial.target
- Remove the Software Site http://download.eclipse.org/releases/luna/ by selecting it in the Locations section and then clicking Remove
- Add a new Software Site by clicking Add… in the Locations section
- Select Software Site
- Software Site for the e(fx)clipse 1.2.0 release build
http://download.eclipse.org/efxclipse/runtime-released/1.2.0/site - Expand FX Target and check Target Platform Feature
Note: RCP e4 Target Platform Feature only contains fx plugins for helping adding JavaFX content to e4-SWT-RCP applications - Uncheck Include required software
- Click Finish
- Activate the target platform by clicking Set as Target Platform in the upper right corner of the Target Definition Editor

Step 2: Migrate the Application Project
- Update the application model
The application model itself is UI toolkit independent. But the binding addons are not. Therefore the default SWT binding addons need to be replaced with the corresponding JavaFX counterpart.- Open the file Application.e4xmi in the project de.codecentric.eclipse.tutorial.app
- Expand the Addons tree node under Application
- Remove the addon org.eclipse.e4.ui.bindings.service
(org.eclipse.e4.ui.bindings.BindingServiceAddon) - Add a new addon
- ID: org.eclipse.fx.ui.keybindings.e4.service
- Class:
bundleclass://org.eclipse.fx.ui.keybindings.e4/org.eclipse.fx.ui.keybindings.e4.BindingServiceAddon
- Remove the addon org.eclipse.e4.ui.workbench.bindings.model
(org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon) - Add a new addon
- ID: org.eclipse.fx.ui.keybindings.e4.model
- Class:
bundleclass://org.eclipse.fx.ui.keybindings.e4/org.eclipse.fx.ui.keybindings.e4.BindingProcessingAddon
- Update the bundle dependencies
- Open the file MANIFEST.MF in the project de.codecentric.eclipse.tutorial.app
- Switch to the Dependencies tab
- Remove the following bundles from the Required Plug-ins
- javax.inject
- org.eclipse.core.runtime
- org.eclipse.swt
- org.eclipse.jface
- Add the following bundles to the Required Plug-ins
- org.eclipse.fx.ui.workbench.fx
- org.eclipse.fx.ui.theme
- org.eclipse.fx.ui.di
- org.eclipse.fx.ui.services
- org.eclipse.e4.core.services
- org.eclipse.e4.core.di.extensions
- Ensure the following bundles are set
- org.eclipse.e4.ui.model.workbench
- org.eclipse.e4.core.di
- org.eclipse.e4.ui.di
- org.eclipse.e4.core.contexts
- org.eclipse.e4.ui.workbench
- org.eclipse.e4.ui.services
- Add the following packages to the Imported Packages
- javax.annotation (1.0.0)
- javax.inject (1.0.0)
- javafx.*

- Update the extension points
- Open the file plugin.xml in the project de.codecentric.eclipse.tutorial.app
- Switch to the Extensions tab
- Update product extension point
- Set application to org.eclipse.fx.ui.workbench.fx.application
- Add a new property to the product extension point
- Right click on the product extension point → property
- name applicationXMI
- value de.codecentric.eclipse.tutorial.app/Application.e4xmi
Note that e(fx)clipse does only support theme based CSS styling. Therefore the applicationCSS property of the product extension point does not have an effect in e(fx)clipse 1.2.0 and can be removed. The recommended way to configure a theme is via declarative service as explained here. Since there is no CSS styling in the basic recipe, we don’t have to perform any migration actions here.
Step 3: Migrate the Plug-in Project
- Update the bundle dependencies
- Open the file MANIFEST.MF in the project de.codecentric.eclipse.tutorial.inverter
- Switch to the Dependencies tab
- Remove the following bundles from the Required Plug-ins
- org.eclipse.swt
- org.eclipse.jface
- Add the following packages to the Imported Packages
In the basic recipe, the plug-in project is the only place where we directly get in touch with JavaFX. In the part implementation, UI toolkit controls are used to create the visible part of the application. Therefore the InverterPart
needs to be re-implemented for the usage of JavaFX.
The first thing to look at are the containers. A JavaFX application basically consists out of two containers, the Stage
which is the main/top-level container, and the Scene
which is the background container for UI elements, that can be exchanged on the Stage
. Within a Scene
, UI elements are arranged in a hierarchical scene graph, that typically has a layout pane as the root node.
Using the e(fx)clipse runtime, the Stage
and the Scene
are managed by the renderer. Within a part we start with a layout pane where the UI elements can be placed on. By default this is javafx.scene.layout.BorderPane
. This can be adjusted by setting a tag to the part definition in the application model. The list of available tags can be found in the Eclipse Wiki.
In SWT layouts are managed by creating a layout instance and setting it to a control. In the basic recipe based on SWT the parent org.eclipse.swt.widgets.Composite
is injected and a org.eclipse.swt.layout.GridLayout
is set it. To show a one-to-one migration, we will also use a grid layout in the JavaFX version. As the layout is specified by the node itself, we use the javafx.scene.layout.GridPane
as parent container, were the other controls will be added to. Note that our simple layout could also be achieved using for example a combination of wrapped javafx.scene.layout.VBox
and javafx.scene.layout.HBox
instances.
- Specify
javafx.scene.layout.GridPane
as the root container of the InverterPart
- Open the file Application.e4xmi in the project de.codecentric.eclipse.tutorial.app
- Select the part in the application model
Application → Windows and Dialogs → Trimmed Window → Controls → PartSashContainer → Part - Switch to the Supplementary tab on the right side of the part details
- Add the tag Container:GridPane via Tags input field
- Open the
InverterPart
in the project de.codecentric.eclipse.tutorial.inverter- Change the type of the parent parameter for the
postConstruct()
method from Composite
to GridPane
- Delete the line that sets the
GridLayout
, since the GridPane
is already our layout pane - Exchange the control implementations. Use the default constructor for every JavaFX control.
org.eclipse.swt.widgets.Label
→ javafx.scene.control.Label
org.eclipse.swt.widgets.Text
→ javafx.scene.control.TextField
org.eclipse.swt.widgets.Button
→ javafx.scene.control.Button
- Set the layout constraints for the controls
The finished part might look similar to the following snippet:
package de.codecentric.eclipse.tutorial.inverter.part;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javax.annotation.PostConstruct;
import de.codecentric.eclipse.tutorial.inverter.helper.StringInverter;
public class InverterPart {
@PostConstruct
public void postConstruct(GridPane parent) {
Label inputLabel = new Label();
inputLabel.setText("String to revert:");
GridPane.setConstraints(inputLabel, 0, 0);
GridPane.setMargin(inputLabel, new Insets(5.0));
final TextField input = new TextField();
GridPane.setConstraints(input, 1, 0);
GridPane.setHgrow(input, Priority.ALWAYS);
GridPane.setMargin(input, new Insets(5.0));
Button button = new Button();
button.setText("Revert");
GridPane.setConstraints(button, 2, 0);
GridPane.setMargin(button, new Insets(5.0));
Label outputLabel = new Label();
outputLabel.setText("Inverted String:");
GridPane.setConstraints(outputLabel, 0, 1);
GridPane.setMargin(outputLabel, new Insets(5.0));
final Label output = new Label();
GridPane.setConstraints(output, 1, 1);
GridPane.setColumnSpan(output, 2);
GridPane.setHgrow(output, Priority.ALWAYS);
GridPane.setMargin(output, new Insets(5.0));
button.setOnMouseClicked((e) ->
output.setText(StringInverter.invert(input.getText())));
input.setOnKeyPressed(event -> {
if (KeyCode.ENTER.equals(event.getCode())) {
output.setText(StringInverter.invert(input.getText()));
}
});
// don't forget to add children to gridpane
parent.getChildren().addAll(
inputLabel, input, button, outputLabel, output);
}
} |
package de.codecentric.eclipse.tutorial.inverter.part; import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority; import javax.annotation.PostConstruct; import de.codecentric.eclipse.tutorial.inverter.helper.StringInverter; public class InverterPart {
@PostConstruct
public void postConstruct(GridPane parent) {
Label inputLabel = new Label();
inputLabel.setText("String to revert:");
GridPane.setConstraints(inputLabel, 0, 0);
GridPane.setMargin(inputLabel, new Insets(5.0));
final TextField input = new TextField();
GridPane.setConstraints(input, 1, 0);
GridPane.setHgrow(input, Priority.ALWAYS);
GridPane.setMargin(input, new Insets(5.0));
Button button = new Button();
button.setText("Revert");
GridPane.setConstraints(button, 2, 0);
GridPane.setMargin(button, new Insets(5.0));
Label outputLabel = new Label();
outputLabel.setText("Inverted String:");
GridPane.setConstraints(outputLabel, 0, 1);
GridPane.setMargin(outputLabel, new Insets(5.0));
final Label output = new Label();
GridPane.setConstraints(output, 1, 1);
GridPane.setColumnSpan(output, 2);
GridPane.setHgrow(output, Priority.ALWAYS);
GridPane.setMargin(output, new Insets(5.0));
button.setOnMouseClicked((e) ->
output.setText(StringInverter.invert(input.getText()))); input.setOnKeyPressed(event -> {
if (KeyCode.ENTER.equals(event.getCode())) {
output.setText(StringInverter.invert(input.getText()));
}
});
// don't forget to add children to gridpane
parent.getChildren().addAll(
inputLabel, input, button, outputLabel, output);
}
}
Step 4: Migrate the Product Configuration
- Open the file de.codecentric.eclipse.tutorial.app.product in the project de.codecentric.eclipse.tutorial.product
- Switch to the Overview tab
- Uncheck The product includes native launcher artifacts
- Update the Product Definition
- Application: org.eclipse.fx.ui.workbench.fx.application
- Switch to the Dependencies tab
- Remove
- org.eclipse.e4.rcp
- org.eclipse.emf.ecore
- org.eclipse.emf.common
- Add
- org.eclipse.fx.runtime.e4fx.feature
- Switch to the Launching tab
- Add -nosplash to the Program Arguments
- Add -Dosgi.framework.extensions=org.eclipse.fx.osgi to the VM Arguments
Step 5: Taste
- Start the application from within the IDE
- Open the Product Configuration in the de.codecentric.eclipse.tutorial.product project
- Select the Overview tab
- Click Launch an Eclipse Application in the Testing section
- Export the application and start the deliverable
- Open the Product Configuration in the de.codecentric.eclipse.tutorial.product project
- Select the Overview tab
- Click Eclipse Product export wizard in the Exporting section
- Select a directory to export to in the Destination section of the export wizard
- Leave the other options unchanged
- Click Finish
- After the export is done, open the directory the application was exported to and start the application by executing the following command on the command line
java -jar plugins/org.eclipse.equinox.launcher_$VERSION.jar
In both cases the application should look similar to the following screenshot.

- Troubleshooting
- In case the application does not start, showing for example ClassCastExceptions, ensure to clean the workspace and the configuration directory.
- Run → Run Configurations → Select the run configuration for the application (Eclipse Application – de.codecentric.eclipse.tutorial.app.product)
- On the Main tab check Clear in the Workspace Data section
- On the Configuration tab check Clear the configuration area before launching in the Configuration Area section
Step 6: Delivery
With the above setup, the export will not generate an executable. We have chosen this setup because the preferred way to export a runnable JavaFX application is by using the JavaFX Packager Tool. On Windows and Linux the PDE export in Eclipse also works, so you basically have two options to create an application that can be delivered with an executable:
- Create an export via PDE export (only Windows and Linux)
- Open the target definition de.codecentric.eclipse.tutorial.target.target in the project de.codecentric.eclipse.tutorial.target
- Add a new Software Site
- Add a new Software Site by clicking Add… in the Locations section
- Software Site http://download.eclipse.org/releases/luna
- Disable Group by Category and filter for Eclipse
- Select Eclipse Platform Launcher Executables
- Activate the target platform by clicking Set as Target Platform in the upper right corner of the Target Definition Editor
- Open the file de.codecentric.eclipse.tutorial.app.product in the project de.codecentric.eclipse.tutorial.product
- Switch to the Overview tab
- Check The product includes native launcher artifacts
- Export and verify that the exported product contains an executable that starts the application
- Create a self contained application package via JavaFX Packager Tool
- To package the application ensure that you already exported the application like shown in Step 5.
- To use the JavaFX Packager Tool you need to create a build.xml file. A good starting point is the build.xml created by the e4 JavaFX application wizard
- Create a temporary e4 JavaFX project
- File → New → Other → JavaFX → OSGI → e4 Application projects
- Enter temp as Bundle-ID-Prefix
- Enter temp as Product Name
- Ensure Tycho Build Stubs is checked
- Ensure Native Packaging is checked
- Create a new release engineering project
- File → New → Project → General → Project
- Set name to de.codecentric.eclipse.tutorial.releng
- Copy the following files from the temporary application releng project to the newly created releng project
- org.eclipse.fx.ide.ant.jar
- build.xml
- Modify the build.xml
- Change the eclipse–app-dir property to the directory the application was exported to
- Also update the fileset with the id equinox-launcher to point to that directory
You can reuse the eclipse-app-dir property
<fileset id="equinox-launcher" dir="${eclipse-app-dir}">
- Update the application name in fx:application and fx:info
- Execute the build
- Right click on build.xml → Run As → Ant Build
- Refresh the de.codecentric.eclipse.tutorial.releng project
- the sub-directory deploy/bundles contains a deliverable application with an executable
- Delete the temporary created projects
You can also find the finished migration on GitHub.
I’m curious to hear if the migration steps work for you and what further recipes you are interested in or if you faced any issues regarding such a migration. Feel free to contact me via email or comments section.