FXML is a declarative way to define you JavaFX UIs, you can edit it by hand e.g. useing e(fx)clipse, use a DSL like FXGraph or use a WYSIWYG-Tool like SceneBuilder.
At runtime a class named FXMLLoader takes the FXML and creates a SceneGraph out of it using reflection. Let’s look at a small sample.
FXML:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.control.Button?> <BorderPane xmlns:fx="http://javafx.com/fxml"> <center> <Button text="Hello World"></Button> </center> </BorderPane>
Loading in Java:
BorderPane p = FXMLLoader.load(getClass().getClassLoader().getResource("Sample.fxml"));
Simple & easy BUT it is slow. On desktop system the slowness might not bother you but on constrainted devices like Raspberry Pi or smartphone reflection it will.
So the idea I had already since some time [Bug] is to move translation from runtime to build time so that one can simply add an instruction to the build script and FXML-Files are translated to Java-Files and compiled by the Java compiler.
While not yet complete I can now share the first version which does at least supports the most basic stuff. To build my JavaFX app which uses FXML I can now use an ant-file like this:
<project default="test"> <path id="fxcompile"> <filelist> <file name="build/classes"/> <file name="build-libs/org.eclipse.fx.fxml.compiler_0.9.0-SNAPSHOT.jar"/> </filelist> </path> <path id="buildpath"> <filelist> <file name="build/classes"/> <file name="libs/org.eclipse.fx.core_0.9.0.201308281625.jar"/> </filelist> </path> <target name="test"> <delete dir="build" /> <mkdir dir="build/classes"/> <taskdef name="fxml-compiler" classpathref="fxcompile" classname="org.eclipse.fx.ide.fxml.compiler.ant.FXMLCompilerTask" /> <javac srcdir="src" destdir="build/classes" classpathref="buildpath"></javac> <fxml-compiler sourcedir="src" destdir="build/gen-src"/> <javac srcdir="build/gen-src" destdir="build/classes" classpathref="buildpath"></javac> </target> </project>
The important line is <fxml-compiler… which instructs the build to translate all FXML-Files found below src into .java-Files and place them into build/gen-src.
Generated Java-File:
import javafx.fxml.FXMLLoader; import javafx.scene.layout.BorderPane; import javafx.scene.control.Button; import java.util.Map; import java.net.URL; import java.util.ResourceBundle; import org.eclipse.fx.core.fxml.FXMLDocument; import java.util.HashMap; @SuppressWarnings("all") public class Sample extends FXMLDocument<BorderPane> { private Map<String,Object> namespaceMap = new HashMap<>(); public Object getController() { return null; } public BorderPane load(URL location, ResourceBundle resourceBundle) { BorderPane root = new BorderPane(); { Button e_1 = new Button(); e_1.setText("Hello World"); root.setCenter(e_1); } return root; } }
In the original code the only change I have to make is switch from FXMLLoader to a smarter class which first checks if there is a .class-File with the same name and create an instance of it.
ExtendedFXMLLoader loader = new ExtendedFXMLLoader(); loader.load(getClass().getClassLoader(),"Sample.fxml");
You can play with it yourself. I’ve uploaded a sample project to http://downloads.efxclipse.org/fxml-compiler.zip, give it a try on your own FXML-Files and if things fail file bugs against e(fx)clipse.
Great job this is the so important feaure that was missing for FXML ! I hope that FXML will leverage MXML features.
What about creating a maven plugin too ?
I don’t know maven, file a bug and contribute it 😉
Pingback: JavaFX links of the week, September 2 // JavaFX News, Demos and Insight // FX Experience
Pingback: Java desktop links of the week, September 2 « Jonathan Giles
Is it possible to download this tool by itself as a jar file?
One thing I don’t like about fxml is that it needs all-permission to do the binding. Does generating the java class file prevent the need of the reflection API for the binding of the fxml to the controller?
Thanks,
The sample project holds the tool jar. On reflection if fields and methods in your controller are public no reflection is used.
Tx, I’ll have a look.
Please note this alpha code so not all fxml files will translate and before i forget there’s still one reflection call needed
I’ve given it a try…
I am trying to run the FXGraphCompiler directly but get an
org.xml.sax.SAXException: javafx.geometry.Insets.getId();
java.lang.NoSuchMethodException…
Looking forward to see the progress you make on this project.
Ok so your inset has an id attribute? Can you show me the part of the fxml where the inset is defined?
HiTom,
I deleted the id on the Insets in the fxml.
The next problem I got was having a combobox which had three default items which the parse could not handle. I tried removing the fxcollections underneath but then I got another error which said something about parameter count.
Maybe I can send you the fxml?
Sure tom dot schindl at bestsolution dot at
I have sent the file, if you do not receive it let me know.
Thanks.
Received it but did not yet have time to take a look
Looks great! A maven plugin would be great, if you need help let me know.
File a bug and contribute a patch 🙂
where can i get the latest fxml-compiler.zip or its related files. which files are needed from efxclipse nitely build area to update your distribution?
You can get the nightly build jar from http://download.eclipse.org/efxclipse/compiler-nightly/org.eclipse.fx.fxml.compiler_0.9.0-SNAPSHOT.jar
I got this exception while trying to bulild.
JRE : 1.7.40
Eclipse Kepler.
Buildfile: D:\Jack\Workspaces\JavaFX\CompilerTest\build.xml
test:
[delete] Deleting directory D:\Jack\Workspaces\JavaFX\CompilerTest\build
[mkdir] Created dir: D:\Jack\Workspaces\JavaFX\CompilerTest\build\classes
[javac] D:\Jack\Workspaces\JavaFX\CompilerTest\build.xml:25: warning: ‘includeantruntime’ was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 5 source files to D:\Jack\Workspaces\JavaFX\CompilerTest\build\classes
[fxml-compiler] Compiling D:\Jack\Workspaces\JavaFX\CompilerTest\src\demo\Login.fxml
BUILD FAILED
D:\Jack\Workspaces\JavaFX\CompilerTest\build.xml:27: java.lang.NoSuchMethodError: java.lang.reflect.Constructor.getParameterCount()I
Total time: 5 seconds
IIRC this method was introduced in JDK8, IIRC I fixed it in the nightly builds. Can you try http://download.eclipse.org/efxclipse/compiler-nightly/org.eclipse.fx.fxml.compiler_0.9.0-SNAPSHOT.jar
Hi Tom,
I got the same exception as Vimal raj and fixed it with the mentioned nightly. But I get another exception:
BUILD FAILED
C:\Workspaces\CompilerTest\build.xml:24: java.lang.NoSuchMethodError: java.lang.reflect.Type.getTypeName()Ljava/lang/String;
This is when running on java7 – i used jdk8 APIs
I’m not able to update to Java8, because of our project requirements.
Can it be fixed for java7?
Can I use your compiler with jdk8 and compile the generated javafx classes with java7?
Yes please file a bug – but just to make sure you’d only need it for compile time not runtime!
Hi there
This is great work! However, the link to the nightly builds doesn’t work. Do you have another link?
The released version is http://download.eclipse.org/efxclipse/compiler-released/0.9.0/org.eclipse.fx.fxml.compiler_0.9.0.jar
Hi! This sounds very promising, as I am also about to run into performance issues loading FXMLs. Is this project still alive? The download link is dead unfortunately.
Yeah blog links are often going stale, the project is alive and we are planing to improve it in the next release. I’m currently unable to give you the URL but the tool is built as part of our nightly CI job
I’ve checked in a sample which uses the FXML => Java compiler at http://git.eclipse.org/c/efxclipse/org.eclipse.efxclipse.git/tree/demos/org.eclipse.fx.samples.fxml.compiler
thanks a lot, also for the quick reply to my filed bugs 🙂 keep up the good work!
Why did this useful tool dissapeared?
It did not disappear but is still available from our eclipse download page
Tom, first congrats for the great job you have done. However, the latest version you released(1.2.0) does not include the org.eclipse.fx, and moreover the ” org.eclipse.fx.ide.fxml.compiler.ant.FXMLCompilerTask, therefore I cannot compile. Have you released any version that supports “fx:include”?
No we have not worked on fx:include IIRC
Hi Tom,
I’ve got the same question like Johny HP. The FXMLCompiler seems to be absent from the org.eclipse.fx.fxml.compiler_1.2.0-SNAPSHOT.jar artifact. Is that an ommission or by design – maybe the package moved to some other artifact? If so into which one?
Also, referring to:
http://download.eclipse.org/efxclipse/?d
… in folder:
http://download.eclipse.org/efxclipse/compiler-released/1.1.0/?d
… the artifact org.eclipse.fx.fxml.compiler_1.1.0-SNAPSHOT.jar does indeed contain the compiler package along with the ant task.
So is 1.1.0 the latest usable Version or alternatively would it be worthwile to git clone https://git.eclipse.org/r/efxclipse/org.eclipse.efxclipse and build it myself? There the classes in question seem to be in https://git.eclipse.org/c/efxclipse/org.eclipse.efxclipse.git/tree/bundles/tooling/org.eclipse.fx.ide.fxml.compiler/src/org/eclipse/fx/ide/fxml/compiler.
Best,
Christian
Yes you currently need to checkout the stuff from the repo. We wanted to provide a standalone app with 2.1.0 but did not have enough resources
I tried running this in Eclipse with Ant using the FXML compiler from the version 2.1.0 e(fx)clipse plugin on Eclipse Mars and JDK 1.8.0_60, but I always get the following error:
1) Error injecting constructor, org.eclipse.emf.common.util.WrappedException: java.lang.ClassCastException: org.eclipse.xtext.resource.XtextPlatformResourceURIHandler cannot be cast to org.eclipse.emf.ecore.xmi.XMLResource$URIHandler
Parts of the stacktrace:
Caused by: org.eclipse.emf.common.util.WrappedException: java.lang.ClassCastException: org.eclipse.xtext.resource.XtextPlatformResourceURIHandler cannot be cast to org.eclipse.emf.ecore.xmi.XMLResource$URIHandler
at org.eclipse.xtext.parser.BaseEPackageAccess.loadResource(BaseEPackageAccess.java:57)
[…]
at org.eclipse.fx.ide.fxgraph.FXGraphStandaloneSetupGenerated.createInjectorAndDoEMFRegistration(FXGraphStandaloneSetupGenerated.java:21)
at org.eclipse.fx.ide.fxml.compiler.ant.CompilerTask.execute(CompilerTask.java:75)
[…]
The last lines are the first time org.eclipse.fx appears in the trace.
Any ideas? Is this to do with your plugin or is it an incompatibility between Eclipse plugins? Would you like me to email you the full stacktrace somewhere?
We did not manage to update the fxml-compiler in 2.1.0 😦 – You can file a bug so that we fix this and svg2 fxml converter in 2.2.0
There is a bug when the FXML has a tag inside.
Example FXML part:
..
The Exception is:
org.xml.sax.SAXException: javafx.scene.layout.AnchorPane.getDefine()
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1261) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:333) ~[na:1.8.0_20]
at javax.xml.parsers.SAXParser.parse(SAXParser.java:195) ~[na:1.8.0_20]
at org.eclipse.fx.ide.fxml.compiler.FXGraphCompiler.compileFXML(FXGraphCompiler.java:98) ~[compiler-0.9.0.jar:na]
at com.proemion.linde.fdatool.FXMLToJava$1.visitFile(FXMLToJava.java:58) [classes/:na]
at com.proemion.linde.fdatool.FXMLToJava$1.visitFile(FXMLToJava.java:1) [classes/:na]
at java.nio.file.Files.walkFileTree(Files.java:2670) [na:1.8.0_20]
at java.nio.file.Files.walkFileTree(Files.java:2742) [na:1.8.0_20]
at com.proemion.linde.fdatool.FXMLToJava.main(FXMLToJava.java:47) [classes/:na]
Caused by: java.lang.NoSuchMethodException: javafx.scene.layout.AnchorPane.getDefine()
at java.lang.Class.getMethod(Class.java:1773) ~[na:1.8.0_20]
at org.eclipse.fx.ide.fxml.compiler.ReflectionHelper.getValueType(ReflectionHelper.java:404) ~[compiler-0.9.0.jar:na]
at org.eclipse.fx.ide.fxml.compiler.FXMLSaxHandler.startElement(FXMLSaxHandler.java:170) ~[compiler-0.9.0.jar:na]
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2786) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) ~[na:1.8.0_20]
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) ~[na:1.8.0_20]
… 9 common frames omitted
File a bug with a reproduceable case
Here is new Netbeans plugin to generate java class from fxml document…
http://plugins.netbeans.org/plugin/68619/fxml-2-java-convertor
Can u create it for eclipse as well?
Nope sorry
No worries:) we’ll continue to use FXML until something comes out
Any updates on this? 😉
No we currently don’t have any resources assigned to this task
Can we have support for fxml to java for javafx8 if yes please provide necessary jar and latest sample example with javafx8
Sure if you sponsor it’s development