Java 8 Resource Bundle cannot find file created immediately

Viewed 574
public class TestResourceBundle {
    private static final Path frZoo = Paths.get("./src/Zoo_fr.properties");
    private static final Path enZoo = Paths.get("./src/Zoo_en.properties");

    private static void createFiles() {

        try {
            Files.createFile(frZoo);
            Files.createFile(enZoo);

            try (BufferedWriter enWriter = Files.newBufferedWriter(enZoo);
                 BufferedWriter frWriter = Files.newBufferedWriter(frZoo);) {
                enWriter.write("hello=Hello\nopen=The zoo is open");
                frWriter.write("hello=Bonjour\nopen=Le zoo est ouvert");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void createBundle() {
        Locale us = new Locale("en", "US");
        Locale france = new Locale("fr", "FR");

        ResourceBundle usBundle = ResourceBundle.getBundle("Zoo", us);
        ResourceBundle frBundle = ResourceBundle.getBundle("Zoo", france);

        System.out.println(usBundle.getString("hello"));
        System.out.println(frBundle.getString("hello"));
    }
}

In the main function, if I run the following, it will throw java.util.MissingResourceException

public static void main(String[] args) {
        createFiles();
        createBundle();
}

but if I run these two functions separately (in two programs), it works and does not have any problem.

First run

public static void main(String[] args) {
        createFiles();
        // createBundle();
}

then run the following, in this case, it works

public static void main(String[] args) {
        // createFiles();
        createBundle();
}

I don't know why, please help

1 Answers

The problem is that you are trying to load a bundle that is not present in the classpath the application knows about.

When you call ResourceBundle.getBundle it will try to load the resource bundle from the application classpath. But the application classpath was already defined at the application startup, so your brand new files are not listed there.

Two options I can think of: Load the bundle from a file input stream or, define your own classloader to load the files.

1. Load the bundle from a File Input Stream

Create a new PropertyResourceBundle from a FileInputStream that loads each file directly.

Warning: Stream closing and exception handling omitted for brevity.

FileInputStream enFileStream = new FileInputStream("./src/Zoo_en.properties");
FileInputStream frFileStream = new FileInputStream("./src/Zoo_fr.properties");

ResourceBundle usBundle = new PropertyResourceBundle(enFileStream);
ResourceBundle frBundle = new PropertyResourceBundle(frFileStream);

2. Create a URL ClassLoader to load the new files

This is a more scalable approach. Create a new URLClassLoader and use that class loader as an argument for getBundle.

Warning: Stream closing and exception handling omitted for brevity.

File bundleRootPath = new File("./src");
URL[] urls = new URL[]{bundleRootPath.toURI().toURL()};
ClassLoader classLoader = new URLClassLoader(urls);

ResourceBundle usBundle = ResourceBundle.getBundle("Zoo", us, classLoader);
ResourceBundle frBundle = ResourceBundle.getBundle("Zoo", france, classLoader);

Hope that helps.

Related