Spring, JavaFX, internationalization and modularisation

时间:2018-12-03 12:56:39

标签: java spring javafx

Related : https://www.javacodegeeks.com/2013/03/javafx-2-with-spring.html and How to handle multiple files and messages for internationalization in Spring?

I have currently and application that mix spring and JavaFX together following the method given in the first link.

At start, I had only one il8n file for everything, however things grow over time and it's now time to split that file. The whole application is already divided in module. One of the last things to do is to split that global file.

Currently things are simple : I use a static class holding the reference to the correct bundle :

private static ApplicationContext SPRING_CONTEXT;
private static ObjectProperty<ResourceBundle> resourceBundleWrapper;

public JavaFxLoader(ApplicationContext context, 
    ObjectProperty<ResourceBundle> resourceBundle){
    SPRING_CONTEXT = context;
    resourceBundleWrapper = resourceBundle;
}

Problem start when I want to have possibly different files for different module.

We'll assume :

  • Each component is independant and don't depends directly of two different bundle.
  • It is possible for a component to have two child component each of them pointing to a different file.
  • I use FXML, so I can't pass in my Control Object a MessageSource directly, however it can get injected in the Controller.

So basically all my specific control look like this :

public class MyCustomControl extends Control {
    private static final java.net.URL FXML_PATH = JavaFxLoader.makeFXMLPath(MyCustomControl .class,
            "my-custom-control.fxml");
    ...

    public MyCustomControl () {


    }

    @Override
    protected Skin<?> createDefaultSkin() {
        return new DefaultSkin();
    }

    private class DefaultSkin extends VBox implements Skin<MyCustomControl> {
        public DefaultSkin(MyCustomControl control) {
            MyCustomControlController controller = JavaFxLoader.loadFXML(this,
                    MyCustomControlController .class, FXML_PATH);
           //post-intialisation of controller by giving the reference to the control
            controller.initData(control);
        }

        @Override
        public MyCustomControl getSkinnable() {
            return control;
        }

        @Override
        public Node getNode() {
            return this;
        }

        @Override
        public void dispose() {
            // TODO Auto-generated method stub
        }
    }
}

Note that sometimes I need to construct Control object myself, so I will instantiate it directly instead of having the FXMLLoader doing it for me.

The problem with my current code lies in the loadFXML method :

public static <T> T loadFXML(Object owner, Class<T> controllerClass, URL fxmlPath){
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setResources(resourceBundleWrapper.get());
    fxmlLoader.setController(SPRING_CONTEXT.getBean(controllerClass));
    fxmlLoader.setLocation(fxmlPath);
    fxmlLoader.setRoot(owner);
    try {
        fxmlLoader.load();
        return fxmlLoader.<T>getController();
    } catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

Currently there is no way for me to specify a specific bundle.

So my question is : what would be the proper way to do that ?

  • Configure a map of package and resource bundle and do some magic reflectivity based on package controler's name to guess which bundle I should use. I'd rather avoid that.
  • Storing statically each bundle resource instance in a class for each module and adding a new parameter to the loadFXML function : the MessageSource instance. I Have already static reference to the general JavaFXLoader utility, I am not sure if it's worth adding others raw static references.
  • Find a way to get all required bundles and put them all together in one bundle for all. For the sake of that we'll assume each key are unique for all MessageSource/RessourceBundle.

I would prefer the last way of doing that however for that, it means I would need :

  • In each module, define a string pointing to its bundles
  • In the principal module configuration class of the whole application find a way to collect all these strings together and instantiate one MessageSource for all.

The configuration is loaded :

  • Eagerly, no lazy-loading of beans (some internal beans have lazy-loading of their datas)
  • Using Annotations only. Even in Controller, I don't care about the coupling between spring and my controller. However I don't inject the springContext in myController, the dependency only lies in the annotation @Autowired/@Qualifier used.
  • No Spring-Boot, Spring-Context only.

0 个答案:

没有答案