Announcing e(fx)clipse DriftFX – Integrating Native Rendering Pipelines into JavaFX

I’ve had the honor to introduce DriftFX at todays JavaFX-Days conference in Zürich.

What is DriftFX

DriftFX is a JavaFX extension allowing you to embed native rendering engines (eg OpenGL) into the JavaFX-Scenegraph.

To embed external rendering engines DriftFX exposes a new Node-Type DriftFXSurface one can put at any place in the SceneGraph and treat it like any other JavaFX-Node – you can apply transformations, effects, … on it like you do with any other JavaFX-Node. In general you can think of it as ImageView on steroids.

A more real world example what one can make happen with DriftFX can be seen in this video provide by Netallied a partner company.

What does DriftFX do?

DriftFX allows you to directly embed content rendered by native pipelines into JavaFX WITHOUT going through the Main-Memory. The rendered artifacts stay at the GPU all time!

What DriftFX does not do?

DriftFX is not a rendering engine itself and it does not provide any abstraction layer to write native rendering engines. Its only purpose is to bring your rendered content directly in JavaFX.

What platforms does DriftFX support?

Our Beta implementation currently supports all 3 major Desktop-Systems supported by OpenJFX – Windows, OS-X and Linux.

We currently targeted JavaFX-8 because this is what our customers are running their applications on. We plan to provide support for OpenJFX-11 and future releases of OpenJFX in the week/months to come.

Is DriftFX opensource?

Yes. We’ve been lucky that the sponsors of the work agreed to make DriftFX opensource. Currently there’s an open Pull-Request at Github for the e(fx)clipse project.

Note that it will take some time until the PR is merged. The reason is that we are going to run this through the Eclipse IP-Process to make sure you can safely embed it into your application.

Does DriftFX use internal “APIs”

Yes. It integrates into the JavaFX-Rendering pipeline so it needs to access internals. We are aware that those can change at any time. We are open to contribute DriftFX in future to OpenJFX but it heavily depends on the OpenJFX community and the stewards of OpenJFX.

Is DriftFX production ready?

Propably not 100% yet, we are just about to integrate it into our customers application and fix problems as they arise. So we are somewhere in between Beta and production readiness.

The reason to opensource it now is that we expect the OpenJFX community to take a look and help us improving it. We know that there are many very clever people in the OpenJFX community who can hopefully help us pushing DriftFX forward.

How can you/your company help?

First of all take a look at it and in case it looks interesting get in touch with us to help fund the ongoing work on this matter.

Acknowledgement

First of all I’d like to thank EclipseSource Munich and Netallied for their on going support on DriftFX. Special thank goes out to my co-worker (and partner in crime) Christoph and all other people at BestSolution.at who made DriftFX happen!

Advertisement
Posted in e(fx)clipse | 4 Comments

Building dynamic Java Module System layers to integrate JavaFX 11 in Equinox

One of the most fundamental features of the e(fx)clipse runtime is to integrate JavaFX into the Equinox OSGi-Container and even a running Eclipse IDE.

We currently support the following setups:

  • JavaFX 8
  • JavaFX 9/10
  • JavaFX 11

and the integration for all those versions is a bit different. I don’t want to go into details but starting with JavaFX-11 we need to spin up a new Java-Module-System-Layer at runtime because we can not assume JavaFX being part of the JRE running your OSGi-Container (Eclipse IDE).

Since JavaFX-9 we spin up a dynamic layer to implement JavaFX-SWT-Integration and we adapted that logic for JavaFX-11 to load all JavaFX-11 modules.

The code we have works like this

package javamodules;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SimpleLayerCreation {
private static Path JAVAFX_MODULES = Paths.get("/Users/tomschindl/Downloads/javafx-sdk-11/lib");
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Throwable {
Path[] array = Files.list(JAVAFX_MODULES) //
.filter(p -> {
String name = p.getFileName().toString();
return name.startsWith("javafx.") && name.endsWith(".jar");
}) //
.toArray(i -> new Path[i]);
Set<String> modules = Stream.of(array) //
.map(Path::getFileName) //
.map(Path::toString) //
.map(n -> n.substring(0, n.length() - ".jar".length())) //
.collect(Collectors.toSet());
URL[] urls = Stream.of(array).map( Path::toFile).map( f -> {
try {
return f.toURL();
} catch(Throwable t) {
return null;
}
} ).toArray( i -> new URL[i]);
URLClassLoader c = new URLClassLoader(urls, FeatureRichLayerCreation.class.getClassLoader());
ModuleFinder fxModuleFinder = ModuleFinder.of(array);
ModuleFinder empty = ModuleFinder.of(new Path[0]);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration configuration = bootLayer.configuration();
Configuration newConfiguration = configuration.resolve(fxModuleFinder, empty, modules);
ModuleLayer moduleLayer = bootLayer.defineModulesWithManyLoaders(newConfiguration, FeatureRichLayerCreation.class.getClassLoader());
ClassLoader loader = moduleLayer.findLoader("javafx.base");
System.err.println(loader.loadClass("javafx.beans.property.SimpleStringProperty").newInstance());
System.err.println(loader.loadClass("com.sun.javafx.runtime.VersionInfo").newInstance());
c.close();
}
}
and it works prefectly fine until someone like ControlsFX comes along and does not play by the rules trying to load classes from unexported packages like com.sun.javafx.runtime.VersionInfo.

The standard answer from ControlsFX to fix that problem temporarily is to force the module-system to export them using –add-exports=javafx.base/com.sun.javafx.runtime=ALL-UNNAMED.

Unfortunately this workaround does not work in our case because the command-line flag only allows to modify modules of the Boot-Layer but not those created in dynamic ones like those we construct inside our JavaFX-OSGi integration.

I was investigating yesterday how one could fix this problem but could not come up with a good solution (one that does not call into internals of the module system) until I tweeted

about it and Tom Watson (one of the maintainers of Equinox) pointed me into the right direction.

So the solution is

/*
* For modules on the boot-layer one can add exports using --add-exports but it looks like there's no
* public API to do the same when constructing a custom layer
*/
package javamodules;
import java.lang.ModuleLayer.Controller;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FeatureRichLayerCreation {
private static Path JAVAFX_MODULES = Paths.get("/Users/tomschindl/Downloads/javafx-sdk-11/lib");
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Throwable {
System.err.println("VERSION: " + System.getProperty("java.version"));
Path[] array = Files.list(JAVAFX_MODULES) //
.filter(p -> {
String name = p.getFileName().toString();
return name.startsWith("javafx.") && name.endsWith(".jar");
}) //
.toArray(i -> new Path[i]);
Set<String> modules = Stream.of(array) //
.map(Path::getFileName) //
.map(Path::toString) //
.map(n -> n.substring(0, n.length() - ".jar".length())) //
.collect(Collectors.toSet());
URL[] urls = Stream.of(array).map( Path::toFile).map( f -> {
try {
return f.toURL();
} catch(Throwable t) {
return null;
}
} ).toArray( i -> new URL[i]);
URLClassLoader c = new URLClassLoader(urls, FeatureRichLayerCreation.class.getClassLoader()) {
protected java.lang.Class<?> findClass(String moduleName, String name) {
try {
return findClass(name);
} catch (ClassNotFoundException e) {}
return null;
}
protected URL findResource(String moduleName, String name) throws java.io.IOException {
return findResource(name);
}
};
ModuleFinder fxModuleFinder = ModuleFinder.of(array);
ModuleFinder empty = ModuleFinder.of(new Path[0]);
ModuleLayer bootLayer = ModuleLayer.boot();
Configuration configuration = bootLayer.configuration();
Configuration newConfiguration = configuration.resolve(fxModuleFinder, empty, modules);
Controller moduleLayerController = ModuleLayer.defineModules(newConfiguration, Arrays.asList(bootLayer), s -> c);
ModuleLayer moduleLayer = moduleLayerController.layer();
moduleLayerController.addExports(moduleLayer.findModule("javafx.base").get(), "com.sun.javafx.runtime", FeatureRichLayerCreation.class.getModule());
ClassLoader loader = moduleLayer.findLoader("javafx.base");
System.err.println(loader.loadClass("javafx.beans.property.SimpleStringProperty").newInstance());
System.err.println(loader.loadClass("com.sun.javafx.runtime.VersionInfo").newInstance());
Class<?> loadClass = loader.loadClass("com.sun.glass.utils.NativeLibLoader");
System.err.println(loadClass.getModule());
// we need to overwrite findResource(String,String)
System.err.println(loadClass.getResource("NativeLibLoader.class"));
// we need to overwrite findClass(String,String)
System.err.println(Class.forName(moduleLayer.findModule("javafx.base").get(), "javafx.beans.property.SimpleIntegerProperty"));
c.close();
}
}

and now I have to think how we expose that to in our OSGi-Integration.

Posted in Uncategorized | 6 Comments

Supporting OpenJFX 11 from JDK11 onwards in e(fx)clipse

So starting with JDK-11 OpenJFX is not part of any downloadable distribution. As JavaFX is designed to run on the module-path (and tested only there) you have 2 options to run JavaFX inside OSGi:
* You create your own JDK-Distribution using jlink
* You launch the VM you want to use JavaFX adding the JavaFX-Modules

While the 2nd solution is doable for RCP-Applications it is less than a nice one, and for integrating into external frameworks (like the Eclipse IDE) it is not possible at all. So we need a different solution to satisfy both usecases.

The solution to this problem is that e(fx)clipse installs a classloader hook using the Equinox AdapterHook-Framework (you can do crazy stuff with that) and on the fly spins up a new Java-Module-Layer containing all the JavaFX-Modules and uses the classloader from the Module-Layer to load the JavaFX-Classes.

With this strategy you can supply the JavaFX-Modules (including the native bits) required for your application to run as part of your p2-repository.

Posted in Uncategorized | 6 Comments

Fluent-Log API landed in e(fx)clipse

Last week I came a cross Googles FLogger-API and I really liked it.

Back in e(fx)clipse land I started to miss it but because introducing a dependency to other log-frameworks is not possible – I implemented our own fluent log API inspired by Flogger.

So how do you use it:


// if you have a logger
Logger logger = LoggerCreator.createLogger( Sample.class );
FluentLogger flogger = FluentLogger.of( logger );

// if you use @Log
@Inject
@Log
FluentLogger flogger;

// Log something
FluentLogContext debug = flogger.atDebug();
debug.log( "Hello World" );
debug.log( "Hello World with format %s", 10 );
debug.log( () -> "Lazy Hello World" );
debug.log( t -> "Lazy Hello World with Context" + t, o );

// Log with exception
try {
   // ...
} catch( Throwable l ) {
  flogger.atInfo().withException( t ).log( "Hello World" );
}

// Throttle: Only log every 100 log statement
flogger.atInfo().throttleByCount(100)
  .log( "Log every 100 time" );

// Throttle: Only log every minute
flogger.atInfo().throttleByTime(1, TimeUnit.MINUTES)
  .log( "Log every minute" );

// Build your own condition fluent addition
logger.atInfo().with( Throttle::new ).every( 100 )
  .log( "Log every 100 time" )
Posted in e(fx)clipse | 6 Comments

Proper OSGi access restriction warnings for e(fx)clipse maven projects

In the last few days I worked on the last required feature to abandon PDE and use maven (with the bnd-maven-plugin) and m2e.

Does anyone reading my blog know if IntelliJ and Netbeans also have a feature like this?

Posted in e(fx)clipse, Uncategorized | 4 Comments

Cross IDE Dev-Support for “e4 on JavaFX” – We are almost there

In the last few days I made a major step towards supporting all major Java-IDEs (Eclipse, Netbeans, IntelliJ IDEA) to develop “e4 on JavaFX” applications.

The key to this multi-IDE support is that we don’t use the MANIFEST-First approach from PDE but we use:

  • Maven 3.5
  • bnd-maven-plugin
  • A custom maven-plugin for launching in Netbeans and IntelliJ

Eclipse

For every member on your team who likes the Eclipse IDE.

In Eclipse we use a custom launcher who uses the maven-project dependency information to launch OSGi and install all necessary bundles.

Netbeans

For every member on your team who likes Netbeans

As you notice hot-code replacement is not yet working (or maybe I’m using Netbeans wrong?) Is there anything i need to do after having changed the file to hot-swap it?

IntelliJ IDEA

For every member on your team who likes IntelliJ

As you notice hot-code replacement is not yet working (or maybe I’m using IntelliJ IDEA wrong?) Is there anything i need to do after having changed the file to hot-swap it?

Posted in e(fx)clipse, Uncategorized | 10 Comments

Introducing (another/additional) JavaFX TestFramework

Let me start with the statement that TestFX is somewhat the default JUnit-Testframework for JavaFX application and is what we proposed to use to all our customers and our projects until today where we introduce our own one.

There are 2 different problem vectors we have:

  • A licensing issue we have with it at Eclipse.org: TestFX is licensed under EUPL which to me as a software developer looks ok but it looks like the IP-Department at Eclipse.org is not happy about it and refused me to use it. I don’t blame anyone but need to cope with the situation as is!
  • Implementing JUnit-Tests for OSGi-JavaFX applications: This is a pure technical issue and something we could have solved (although it would have meant to change the way TestFX works) but after having hit the licensing problem my motivation to resolve that problem was not really there

Anyways let’s look at what I’ve started to implement as a replacement for TestFX.

BestSolution FX-Test

First of all we decided for now that we don’t integrate the test-framework into e(fx)clipse but treat it as an independent entity at github and release it under EPL from there.

Writing JUnit-Tests is done by subclassing a base class (current only one available is FXComponentTest) and implementing your JUnit-Tests might look like this:

@Test
public void sample() {
  // Search with a css-selector query
  // and generated a click on the button
  rcontroller().cssFirst(".button").get().click();
}

In contrast to TestFX, tests written with our API can not run directly but you need to decided if you want to:

  • Use a specific runner using @RunWith(FXRunner.class)
  • Use a Rule @FXTest and annotate all UI-Test methods with it

which on the plus-side means that the @Test-methods are executed on the JavaFX-UI-Thread (unlike TestFX where they are executed on another thread most like the main-thread)

For more information that a look at the project README.md.

Let me close this post saying that we are very early in the development and things are still in the flux so we are happy for any feedback we get.

Posted in e(fx)clipse | 6 Comments

e(fx)clipse 3.0.0 is released

e(fx)clipse has been released on June 6th but because of the high load of JavaFX projects we are working on I did not have time to write the public release announcement.

In total we have worked on ~100 tickets most of them adding new features. We also moved our dev infrastructure to github.com and while doing that we’ve split the project into 2 repositories:

We believe that moving to github and the upcoming pure maven-build-story we currently work on in an extra branch will make it easier for others to consume our libraries in none OSGi/Eclipse/e4-Projects.

While we are switching our project structure to pure maven you can already consume our libraries from a maven-repository we host ourselves (see http://maven.bestsolution.at/)

Let’s take a short tour through some of the 3.0 highlights.

Support for Java 9

3.0 is the first release who is fully compatible with Java9 and JPMS. Historically we used non-public APIs and even used reflection to eg “hack” DnD in TabFolder. All code that would be broken in Java9 has been reworked to run on Java8 and Java9.

Some of the none public APIs we used in Java8 have been promoted to public API in Java9 and to support both Java 8 and 9 in the same codebase we extracted those into utility class org.eclipse.fx.ui.controls.JavaFXCompatUtil:

Java 8 Java 9 JavaFXCompatUtil
Window#impl_getWindows() Window#getWindows() getAllWindows()
KeyCode#impl_getChar() KeyCode#getChar() getChar(KeyCode)
KeyCode#impl_getCode() KeyCode#getCode() getCode(KeyCode)

Utilities to work with JavaFX Properties

FXBindings

JavaFX has a Bindings class to setup bindings between different Observables but we missed some features we frequently need in our application code hence we added an org.eclipse.fx.core.bindings.FXBindings who eg has:

  • tenaryBinding(ObservableBooleanValue, ObservableValue<T>, ObservableValue<T>) : Binding<T>
    allowing you to defined if-else in a JavaFX binding way
  • concat(ObservableList<? extends A>...) : ListBinding<A>
    to concat the lists to one and keep the target updated when one of the source lists change
  • concat(String, ObservableValue<T>...) : StringBinding
    concat the lists and concat the items with the given delimiter and keep the binding updated
  • bindContent(List<T>, ObservableList<E>, Function<E, T>) : Subscription
    similar to Bindings.bindContent but allows to use a converter function

A very special feature is a BindingStream you can create with bindStream(ObservableValue<T>) who is similar to Bindings.select but is:

  • Typesafe
  • Provide a Property as the leaf

Let’s look at a concrete example.

class Person {
  public ObjectProperty<Address> address();
}

class Address {
  public StringProperty street() { /* ... */ }
}

class UI {

  ObjectProperty<Person> currentPerson = /* ... */;

  TextField street;

  bindUI() {
     street.textProperty().bindBidirectional( 
      FXBindings.bindStream( currentPerson )
        .map( Person::address )
        .collect( 
           FXCollectors.toProperty( Address::street ) 
        )
     );
  }

}

@ContextValue improvements

@ContextValue is IMHO one of the coolest concepts we introduced in e(fx)clipse to make reuseable components. In 3.0 we added a scope-Property who allows you to fix a publishing scope.

As of 3.0 we support:

  • APPLICATION: Publish the value in the IEclipseContext of the application
  • LOCAL: Publish the value in the local IEclipseContext
  • DYNAMIC: Publish the value using IEclipsContext#modify and the application container is responsible to mark the target context

with DYNAMIC as the default.

ThreadSynchronize improvements

Halt program flow

We added a new API to halt the program flow (NOT the event loop) like this:


ThreadSynchronize t = ...;
TextField username = new TextField();

BlockCondition<String> w = new BlockCondition<>();
username.setOnAction( 
  e -> w.release( username.getText() ) );

System.out.println(t.block( w ));

Headless implementation

We at BestSolution use the MVVM-Pattern for our JavaFX applications and there we fetch data from backend-services in none-ui-threads and so we need to synchronize from a Background- to the UI-thread using ThreadSynchronize.

While things work perfectly fine in the real application because the JavaFX Framework is up and running things fall apart when you test your ViewModel in a headless JUnit-Tests. For that purpose there’s now the possibility to create a ThreadSynchronize instance like this:

ThreadSynchronize t = 
  ThreadSynchronize.createBasicThreadSyncronize(
    new EventLoop()
  );
Posted in e(fx)clipse, Uncategorized | 1 Comment

e(fx)clipse runtime library – Working with the (JavaFX) UI-Thread

When developing UI-Application a very frequent task is

  • to synchronizes yourself back from an worker-thread to the UI-Thread
  • schedule task to run in the future
  • Block the program flow and wait for a condition being met (in SWT called spinning the event loop)

JavaFX 8 has a public API for most of those building blocks (only exception is Event-Loop-Spinning who was an internal API in Java8 and is public API in 9) but using higher level API reduces the boilerplate code you need to implement.

Before we start let’s see how you can access to it in your maven-driven projects (I’m not gradle safey enough to show how it works there) you need to

  • add the efxclipse maven repository (at the time of this writing you need to nightly repository because you need at least 3.0.0)
  • add the following dependency
    <dependency>
      <groupId>at.bestsolution.efxclipse.rt</groupId>
      <artifactId>org.eclipse.fx.ui.controls</artifactId>
      <version>3.0.0-SNAPSHOT</version>
    </dependency>
    

Let’s take a look at some of those APIs and how they can help you write better code:

Writing back from worker thread

Let’s suppose we have a service who returns a search result as a CompletableFuture and we want to push the result – once available – to JavaFX ObjectProperty:

import org.eclipse.fx.core.ServiceUtils;

// Lookup the domain service in the service registry
PersonSearchService service = 
  ServiceUtils.getService(PersonSearchService.class);

ObjectProperty<Person> person = ...;

CompletableFuture<Person> result = 
  service.findByName("Tom","Schindl");

Let’s for a second suppose we can interact with our UI-Toolkit on ANY-Thread we could simply write:

result.thenAccept( person::set );

Unfortunately none of the UI-Toolkits I know would support this because they require you to sync on a special thread called the UI-Thread. JavaFX is not different in this aspect.

Plain JavaFX APIs:

result.thenAccept( p -> {
   Platform.runLater( () ->
     person.set(p);
   );
} );

Using e(fx)clipse’ ThreadSynchronize#asyncExec(T,Consumer<T>):

import org.eclipse.fx.core.ThreadSynchronize;

// ...

// Lookup the thready service in the service registry
ThreadSynchronize threadSync = 
  ServiceUtils.getService(ThreadSynchronize.class).get();

result.thenAccept( p -> {
   threadSync.asyncExec( p, person::set );
});

We got rid of the inner lambda and replaced it with a method reference, so the code got more readable but

Using e(fx)clipse’ ThreadSynchronize#wrap(Consumer<T>):

// ...
result.thenAccept( threadSync.wrap(person::set) );

we can get rid of all outer lambda as well and are back to fairly the same code as if we’d not had to worry about thread-synchronization at all.

Reading from a worker thread

Let’s suppose you have a Timer running who wants to read a JavaFX-Property from a TextField in 1 second from now you’d:

  • You’d better rewrite it to use a Timeline so that no thread sync is needed
  • You’d write the following magic lines of code:
TextField textField = ...

Timer t = new Timer();
t.schedule( new TimerTask() {
  @Override
  public void run() {
    CountDownLatch ll = new CountDownLatch(1);
    AtomicReference<String> data = new AtomicReference<>();
    Platform.runLater( () -> {
      data.set( textField.getText() );
      ll.countDown();
    });
    ll.await();
    String d = data.get();
    // further process the data 
  }
}, 1000 );

Let’s for a moment forget that this code fairly dangerous because it might create a dead lock situation (hence JavaFX only provides Platform.runLater(Runnable)) this is a huge amount of code to write! Let’s see what APIs e(fx)clipse has to improve the situation.

Using ThreadSynchronize#syncExec(Runnable):

ThreadSynchronize threadSync = 
  ServiceUtils.getService(ThreadSynchronize.class).get();

public void run() {
  AtomicReference<String> data = new AtomicReference<>();
  threadSync.syncExec( () -> {
    data.set( textField.getText() );
  } );
  String d = data.get();
  // further process the data 
}

Removes the need for the CountDownLatch

Using ThreadSynchronize#syncExec(Callable<V>, V):

public void run() {
  String d = threadSync.syncExec( textField::getText, "" );
}

Removes the need for the AtomicReference

Using ThreadSynchronize#scheduleExecution(long, Runnable):

ExecutorService s = ...;
threadSync.scheduleExecution( 1000, () -> {
   String data = textField.getText();
   s.submit( () -> ... );
} );

Removes the thread synchronization problems arising from Platform.runLater() call

Using ThreadSynchronize#scheduleExecution(long, Callable<T>) : CompletableFuture<T> :

threadSync.scheduleExecution( 1000, textField::getText )
  .thenAcceptAsync( d -> ... );

Removes the lambda and gets you to the wonderful CompletableFuture-API.

Block program flow

Generally speaking halting the program flow is a discouraged software pattern and you’d better work with Future and callbacks like Consumer but there might be (existing) API you have to support who requires you to halt the program flow and continue after a certain condition has been met.

To support such a usecase e(fx)clipse has org.eclipse.fx.ui.controls.Util#waitUntil( BlockCondition blockCondition ) you can use like this


Pane p = ...;

// Ask for name in an overlay
String askForName() {
  BlockCondition<String> condition = new BlockCondition<>();

  TextField t = new TextField();
  Button b = new Button("Proceed");
  b.setOnAction( e -> { condition.release(t.getText()); } );
  HBox box = new HBox(
    new Label("Name:"),
    t,
    b);
  box.setManaged(false);
  box.autosize();
  box.relocate( 
    p.getWidth() / 2 - box.getWidth() / 2, 
    p.getHeight() / 2 - box.getHeight() / 2 );
  p.getChildren().add( box );
  return Util.waitUntil( condition );
}
Posted in e(fx)clipse | 1 Comment

e4 on JavaFX with the bnd-maven-plugin (with VS Code)

Just a few minutes ago I blogged about our future plans for e(fx)clipse and to show you that we take the things mentionned there really serious I can provide you an initial report on the first 2 points from the the list:

  • Freedom of development style
  • Freedom of development tool

Since its inception the way to develop “e4 on JavaFX” meant:

  • useage Eclipse PDE inside your Eclipse IDE
  • useage Maven-Tycho as the headless build system

We will start to change that and in the weeks to come!

First and most important

We won’t take away ANYTHING – if you want to use PDE and Tycho please do so – we are going to support that development style like did in the past!

The future is pure maven/gradle

I’ve played around a lot in the past weeks with Eclipse, IntelliJ IDEA, Netbeans and VS Code to find what would work out best and I think I’ve reached a point where I can provide you some screenshots and screen casts.

Eclipse

In Eclipse all I need to develop my application is the m2e extension.

screen-maven-pure-eclipse

VS Code

To give me the extra kick I decided to give VS-Code and the Java-Extension from RedHat a shot.

The technology

Now that you have looked at the cool screen-cast let’s talk about the boring technology in the backend. We rely on 2 things:

Posted in Uncategorized | 9 Comments