What is the default path of ResourceBundle.getBundle() to access the properties file

566 views Asked by At

While writing unit tests for a small component that is part of a relatively massive Java Project, I came across the need to use a method in another class TheOtherClassNoPartOfMyProject that will access a .properties file to fetch values used to set up SSLContext. I managed to get the JAR dependency for this class and attached the source code. Luckily, I can debug the other class which is not part of the component I am developing. Eventually, the method executes the following steps:

public class TheOtherClassNoPartOfMyProject {
...
...
    private ResourceBundle resourceBundle = null;
...
...
    public void setLocale(Locale newLocale) throws ACCatastrophicException {
        if (newLocale.equals(locale) && (resourceBundle != null)) {
            return;
        }
        locale = newLocale;
        try {
            resourceBundle = ResourceBundle.getBundle(filename, locale);
        } catch (MissingResourceException e) {
            resourceBundle = null;
            System.out.println("Could not locate properties file for locale '"
                    + locale.toString() + "'");
            throw new ACCatastrophicException("Could not locate "
                    + ACProductVersion.getProductName()
                    + " properties file for locale '" + locale.toString() + "'");
        }
    }
...
...
}

The class TheOtherClassNoPartOfMyProject encapsulates the built-in Java Type ResourceBundle to work with .properties files.

When the test runs, I get the error Could not locate properties file for locale ....

Below is to give more context to the problem I am facing.

The component I am writing needs to create SSLContext and must reuse existing common classes I am facing difficulty in how to reuse such classes while writing unit tests since not all dependencies and required properties files are available for the component I am writing.

I have a valid .properties file which works when deployed under the bin folder of the application root folder of the installed application. However, during development time, I don't have a bin folder in my Maven Project and am not sure where to put this .properties file. Below is the code part to create SSLContext in my Maven Project, class MyService:

public class MyService {
...
    private static SSLContext sslContext=null;
    private static final String TLSV12 = "TLSv1.2";
...
    public void createSSLContext() {
        KeyStore keyStore= null;
        KeyStore trustStore = null;
        InputStream kis =null;
        InputStream tis = null;
        KeyManagerFactory keyManagerFactory = null;
        TrustManagerFactory trustManagerFactory = null;
        try {
            constants = TheOtherClassNoPartOfMyProject.getInstance();
            sslContext = SSLContext.getInstance(TLSV12);
            if (constants.getString("webservice.keystore") != null && !(constants.getString("webservice.keystore").isEmpty())) {
                keyStore = KeyStore.getInstance("JKS");
                kis = new FileInputStream(constants.getString("webservce.keystore"));
                if (constants.getString("webservice.keystore_password") != null && !(constants.getString("webservice.keystore_password").isEmpty())) {
                    String keyPassword = "changeit";
                    keyStore.load(kis,keyPassword.toCharArray());
                    keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    keyManagerFactory.init(keyStore, keyPassword.toCharArray());
                }
            }
            
            if (constants.getString("webservice.truststore") !=null && !(constants.getString("webservice.truststore").isEmpty())) {
                trustStore = KeyStore.getInstance("JKS");
                tis = new FileInputStream(constants.getString("webservice.truststore"));
                if (constants.getString("webservice.truststore_password") != null && !(constants.getString("webservice.truststore_password").isEmpty())) {
                    String trustStorePassword = "changeit";
                    trustStore.load(tis, trustStorePassword.toCharArray());
                }
                trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(trustStore);
            }
            sslContext.init(
                    keyManagerFactory!=null?keyManagerFactory.getKeyManagers():null, 
                    trustManagerFactory!=null?trustManagerFactory.getTrustManagers():null,
                    new java.security.SecureRandom());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

I was thinking to use mockito to mask such methods, but first I wanted to ensure that the code I am writing will work with the existing dependencies. Also, I still need to research how to use mockit.

Where should I put the .properties file so that it can be picked up by ResourceBundle.getBundle()?

1

There are 1 answers

0
tarekahf On

I figured out that I must place the file under src/test/resource or src/main/resources. Also, if you don't qualify the resource name with a package name, then it will look for the file in the base folder of the compiled classes such as target/test-classes. If you qualify the resource name with a package name, it will look for the file in the related folder matching the package name. Note that the file is copied to the relevant folder in the under target/ during compile time.

You can add this test to quickly verify how it works:

    public void testResourceBundle() {
        ResourceBundle rb = ResourceBundle.getBundle("com.fun.resources.SVCInterface", Locale.getDefault());
        System.out.println(rb.getString("some.key"));
        assertThat(rb.getString("some.key"), not(isEmptyOrNullString()));
    }

Since the above code is running from the test folders, you can place the file under src/test/resource/com/fun/resources and name it SVCInterface.properties and it will work. Make sure it has the key some.key=some-value. In Eclipse, it works since when you run the tests, it will include the target folder of the compiled classes in the classpath by default.