Search code examples
javajavafxfxml

Is it possible to refer to converters in JavaFX through FXML?


I'm currently setting my converters (StringConverter) in the Controller, but I was wondering if it was possible to do it straight from the FXML file?

Thanks


Solution

  • An FXMLLoader instantiates types via reflection. This means the class must either have a constructor whose parameters are annotated with @NamedArg or a constructor with zero parameters. The @NamedArg solves the issue of parameter names not necessarily being saved in the byte code, as better explained by this answer. The remaining attributes will be set on the object according to the rules specified in this section of Introduction to FXML. To summarize, the FXML attribute/element must have a corresponding property setter, read-only List property, or read-only Map property in the target class.

    What this all means for your question is:

    1. It depends on the implementation of StringConverter.
      • It must have a no-argument constructor or have @NamedArg annotated constructor parameters.
    2. It depends on the object you're setting the StringConverter on.
      • It must either have a suitably annotated constructor parameter or the property must have a setter. Otherwise the FXML loader won't know how to set the converter.

    Looking at the source code it doesn't look like any of the StringConverter implementations use the @NamedArg annotation. They often do provide a no-argument constructor, however. This will allow you to use them but you may lose the ability to customize them. For instance, when using LocalDateStringConverter you won't be able to customize the format.

    That said, you could always create a factory class and use fx:factory in the FXML file.

    public class Converters {
    
        public static StringConverter<LocalDate> myAwesomeConverter() {
            DateTimeFormatter formatter = ...;
            return new LocalDateStringConverter(formatter, formatter);
        }
    
    }
    
    <DatePicker>
        <converter>
            <Converters fx:factory="myAwesomeConverter"/>
        </converter>
    </DatePicker>
    

    Or if you don't want a custom formatter, you can just use the converter's no-arg constructor.

    <DatePicker>
        <converter>
            <LocalDateStringConverter/>
        </converter>
    </DatePicker>