Creating multiple configs within a directory

I am trying to create multiple configs into a single directory. When I run the server, then new directory is created but the configs don’t create. If I don’t specify the configs to create in that folder, and instead allow them to be created in the server root folder, they get created fine. Here’s my code

@Inject
    @ConfigDir(sharedRoot = false)
    private File configDir;

    private File config = new File(configDir+"tiers.conf");
    private ConfigurationLoader<CommentedConfigurationNode> configManager = HoconConfigurationLoader.builder().setFile(config).build();
    private CommentedConfigurationNode configNode;

    private File playerConfig = new File(configDir+"players.conf");
    private ConfigurationLoader<CommentedConfigurationNode> playerConfigManager = HoconConfigurationLoader.builder().setFile(playerConfig).build();
    private CommentedConfigurationNode playersConfigNode;

    private ConfigurationLoader<CommentedConfigurationNode> getConfigManager(){return configManager;}
    private ConfigurationLoader<CommentedConfigurationNode> getplayerConfigManager(){return playerConfigManager;}

    @Inject
    Game game;


    private static PixelQueue instance;

    @Listener
    public void onPreInitialization(GamePreInitializationEvent e) {
        if (!configDir.exists()) {
            configDir.mkdir();
        }

        try{
            if(!config.exists()){
                config.createNewFile();
                configNode = configManager.load();

                configNode.getNode("ConfigVersion").setValue(1);
                configManager.save(configNode);
                logger.info("created tier config");
            }
            if(!playerConfig.exists()){
                playerConfig.createNewFile();
                playersConfigNode = playerConfigManager.load();


                playersConfigNode.getNode("ConfigVersion").setValue(1);
                playerConfigManager.save(configNode);
                logger.info("created player config");
            }

            configNode = configManager.load();
            playersConfigNode = playerConfigManager.load();

        }catch (IOException Exception){
            logger.info("Couldnt create default config");
        }
    }

None of that explains that actual problem, however (except perhaps for the new File(configDir, "tiers.conf") bit). It actually comes down to how the process that handles the @Inject annotation works.

Sponge uses Dependency Injection (DI) to inject objects into marked fields, as mentioned on our docs, specifically, we use Google’s Guice. In your case, you are performing a field injection, which to those who aren’t familiar with DI or how Java works in general can be confusing and makes it easy to fall into the trap you’ve fallen into here.

What has happened is that when your plugin object is initially created, the fields that have an @Inject annotation on them are null. This is the case until after the object is constructed, while lines where the value is declared inline, such as:

private File config = new File(configDir+"tiers.conf");

are created during initialisation. This means that when your other fields are initialised, such as this one, the value of configDir is null at that point and so you get this issue.

One option is to do this initialisation at pre-init, as suggested, so set the value of configManager etc. during your onPreInitialization method.

Personally, I would rewrite this using a constructor injection instead. What that means is that the injections can be provided during construction rather than initialisation and you can use final modifiers on the fields. So, part of it would be:

    private final Game game;

    private final File config;
    private final ConfigurationLoader<CommentedConfigurationNode> configManager;
    private CommentedConfigurationNode configNode;

    ...

    @Inject
    public PixelQueue(File configDir, Game game) {
        this.game = game;
        this.config = new File(configDir, "tiers.conf");
        this.configManager = HoconConfigurationLoader.builder().setFile(config).build();
    }

You will need to do that with your player config file too - if you choose this route that bit is left as an exercise to you.

You can then do any other task you need in pre-init as required.