Put in the class path:
The challenge is to bring FXMLLoader and CDI together, because JavaFX is creating naked objects by itself, now they have to be „CDI-aware“.
package tutego.fx;
import java.nio.charset.*;
import javafx.fxml.FXMLLoader;
import javafx.util.Callback;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
public class FXMLLoaderProducer
{
@Inject
Instance<Object> instance;
@Produces
public FXMLLoader createLoader()
{
return new FXMLLoader( null, null, null, new Callback<Class<?>, Object>() {
@Override public Object call( Class<?> param ) {
return instance.select( param ).get();
}
}, StandardCharsets.UTF_8 );
}
}
That was the hardest part.
The first regular class has the unique main(String[]) method and it’s a JavaFX application. It starts Weld, the CDI container.
package tutego.fx;
import java.io.IOException;
import javafx.application.Application;
import javafx.stage.Stage;
import org.jboss.weld.environment.se.*;
public class Main extends Application
{
private Weld weld;
public static void main( String[] args )
{
Application.launch( args );
}
@Override
public void init()
{
weld = new Weld();
}
@Override
public void start( Stage stage ) throws IOException
{
weld.initialize().instance().select( FxMain.class ).get().start( stage, getParameters() );
}
@Override
public void stop()
{
weld.shutdown();
}
}
Weld delegates to the FxMain class, the first CDI-enabled class:
package tutego.fx;
import java.io.*;
import javafx.application.Application.Parameters;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;
import javax.inject.Inject;
public class FxMain
{
@Inject
private FXMLLoader fxmlLoader;
public void start( Stage stage, Parameters parameters ) throws IOException
{
try ( InputStream fxml = RandomController.class.getResourceAsStream( "/random.fxml" ) ) {
Parent root = (Parent) fxmlLoader.load( fxml );
stage.setScene( new Scene( root ) );
stage.show();
}
}
}
The injected FXMLLoader now has to load the FXML-file random.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="tutego.fx.RandomController">
<children>
<Button onAction="#onButtonClick" text="Next random" />
<Label id="text" fx:id="label" />
</children>
</VBox>
In the FXML-file there is a reference to the FX Controller. JavaFX has to load it and can make the injections with the help of our very first class. A regular service is getting injected into the controller:
package tutego.fx;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javax.inject.Inject;
public class RandomController
{
@FXML
private Label label;
@Inject
private RandomService randomService;
@FXML
public void onButtonClick()
{
label.setText( "Random " + randomService.nextInt() );
}
}
The service itself is a simple singleton:
package tutego.fx;
import java.util.Random;
import javax.inject.Singleton;
@Singleton
public class RandomService
{
private Random rnd = new Random();
public int nextInt()
{
return rnd.nextInt();
}
}
Thats it!
PS: When you start, dont forget to put a (even blank) beans.xml in META-INF.