Why not use ResourceBundle instead of Properties? - java

This is an easy question to which I can't find a concluding answer.
I can load string properties (e.g.: a query for a prepared statement) from a config.properties file. Let's say I want to take the database connection to which to connect.
If I want to take this information from the file, I could do just the following in a class:
private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("scheduler");
private static final String DRIVER = BUNDLE.getString("bd.driver");
private static final String CONNECTIONURL =BUNDLE.getString("bd.url");
....
But instead I've seen that many people recommend using instead Properties, Then I would have to do the same with something like this (if I want to keep the class static and not have a proper constructor):
static {
prop = new Properties();
try { prop.load(ReportsDB.class.getClassLoader().getResourceAsStream("config.properties"));
} catch (IOException ex) {
Logger.getLogger(ReportsDB.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
private static final String DRIVER = prop.getProperty("bd.driver");
private static final String CONNECTIONURL = prop.getProperty("bd.url");
So, why shouldn’t I use the ResourceBundle instead of Properties when the second one is more verbose?

So, why shouldn’t I use the ResourceBundle instead of Properties when the second one is more verbose?
Because that's not what ResourceBundle is for. The description of the class starts with:
Resource bundles contain locale-specific objects. When your program needs a locale-specific resource, a String for example, your program can load it from the resource bundle that is appropriate for the current user's locale. In this way, you can write program code that is largely independent of the user's locale isolating most, if not all, of the locale-specific information in resource bundles.
Does any of this sound like your use case? I don't think so.
It sounds like the problem is purely the verbosity of loading a properties file: so write a utility method to do that. Then your code can be simply:
private static final Properties CONFIGURATION = PropertyUtil.load("scheduler.properties");
private static final String DRIVER = CONFIGURATION.getString("bd.driver");
private static final String CONNECTIONURL = CONFIGURATION.getString("bd.url");
Admittedly I'm not keen on having static field initializers in an order-dependent way like that... I'd be tempted to encapsulate all of the configuration in a separate class, so you could write:
private static final SchedulerConfiguration CONFIG =
SchedulerConfiguration.load("scheduler.properties");
then use CONFIG.getDriver() etc which could fetch from the properties each time, or use a field, or whatever.

One concrete difference is that ResourceBundle.getBundle("scheduler") will search for the file in the classpath (the src package folder for example). If you call ResourceBundle.getBundle("myfile") on an external file you will get the MissingResourceException.
If you want to use an external file (a file located in the project root for example) you can use the Properties class:
Properties configuration = new Properties();
try (InputStream input = new FileInputStream("configuration.properties")) {
configuration.load(input);
System.out.println("Configuration value: " + configuration.getProperty("key"));
} catch (IOException e) {
e.printStackTrace();
}

Related

Java Singleton Object Multiple Language Data Implement

Assume there is a simple class:
public class SingletonClass {
private static SingletonClass singObj;
private string variable1;
private string variable2;
.....
public static synchronized SingletonClass getInstance() {
if (singObj == null) {
singObj = new SingletonClass();
}
return singObj;
}
}
If there are lot of string variables and they need to be stored in multiple language, what's the standard method to manage this in Java?
Currently i use:
public class SingletonClass {
private static SingletonClass singObj_LANG1;
private static SingletonClass singObj_LANG2;
private static SingletonClass singObj_LANG3;
private string variable1;
private string variable2;
.....
public static synchronized SingletonClass getInstance(String lang) {
if (lang.equals("English")) {
if (singObj_LANG1 == null) {
singObj_LANG1 = new SingletonClass();
}
return singObj_LANG1;
}else if (lang.equals("Chinese")) {
if (singObj_LANG2 == null) {
singObj_LANG2 = new SingletonClass();
}
return singObj_LANG2;
}else{
if (singObj_LANG3 == null) {
singObj_LANG3 = new SingletonClass();
}
return singObj_LANG3;
}
}
}
which i think is a bad practice, any better implementation?
What you need is internationalization
Internationalization is the process of designing an application so
that it can be adapted to various languages and regions without
engineering changes. Sometimes the term internationalization is
abbreviated as i18n, because there are 18 letters between the first
"i" and the last "n."
Instead of a string variable for lang you need to use Locale.
You store the messages in a ResourceBundle.
Resource bundles contain locale-specific objects. When your program needs a
locale-specific resource, a String for example, your program can load
it from the resource bundle that is appropriate for the current user's
locale. In this way, you can write program code that is largely
independent of the user's locale isolating most, if not all, of the
locale-specific information in resource bundles. This allows you to
write programs that can:
be easily localized, or translated, into different languages handle
multiple locales at once be easily modified later to support even more
locales
The Java Platform provides two subclasses of ResourceBundle, ListResourceBundle and PropertyResourceBundle, that provide a fairly simple way to create resources. ListResourceBundle manages its resource as a list of key/value pairs. PropertyResourceBundle uses a properties file to manage its resources.
What i recommend is the PropertyResourceBundle because you should be keeping your translated values in a properties file.
A properties file is a simple text file. You can create and maintain a properties file with just about any text editor.
Read more backing a ResourceBundle with Properties Files here
You can read more about the concept here.
In the end you will end up getting the messing like this:
ResourceBundle messages = ResourceBundle.getBundle("MessagesBundle", currentLocale);
System.out.println(messages.getString("locale.language.key.example"));
The links i provided represent lessons in a wider course on internationalization. You can navigate and read more about it there and you will end up learning the best practices. Using a framework it becomes even easier.
Taking this approach you will be using a single class.
I wouldn't use the Singleton approach at all. Java Internationalization is what you need:
https://docs.oracle.com/javase/tutorial/i18n/intro/steps.html
I would use a Map as storage for your language-specific singletons
private static Map<String, TheClass> map = new HashMap<>();
public static SingletonClass getInstance(String lang) {
synchronized(map){
if(map.containsKey(lang)) return map.get(lang);
else{
SomeClass it = new SomeClass();
map.put(lang, it);
return it;
}
}
}
But the better solution for your problem is Internationalization (see other answers)

Strategy to share static Strings across my app

I have lots of values in properties files, which are read in my app to setup values (DB connections, email servers, etc.).
db.properties:
db.user=admin
db.pwd=secret1234
Now in my DatabaseService class, I have something like this:
private static final String DB_USER = "db.user";
private static final String DB_PWD = "db.pwd";
private Properties dbProps = new Properties();
// read db.properties values into dbProps
String user = dbProps.getProperty(DB_USER);
Then in my DatabaseServiceTest class, I have repeated code:
private static final String DB_USER = "db.user";
private static final String DB_PWD = "db.pwd";
private Properties dbProps = new Properties();
// read db.properties values into dbProps
String user = dbProps.getProperty(DB_USER);
So I have repeated code. So instead I have put the static String values into a StaticVars class that hosts all of the Strings so the DatabaseService and DatabaseServiceTest now look like this (I could also put the Properties in the utility class, but there are scores of this example, so I haven't so far):
private Properties dbProps = new Properties();
// read db.properties values into dbProps
String user = dbProps.getProperty(StaticVars.DB_USER);
Is there a better way to share the static Strings across multiple class files? My current StaticVars class has about 150 static String values, and growing. It seems like I am going down the wrong path.
Thanks,
Sean
I think your general approach - using public static final String members of a public class - is a fine way to share strings across an application.
However don't underestimate the importance of naming. When you come back to this code in 6 months will you remember that the names of your properties are stored in a class called StaticVars? If you are truly only storing property names, then perhaps the class should be called PropertyNames. Now you have bounded the scope of the class and will be less likely mix in strings for error messages or regular expressions or whatever. (Those should go into different classes with meaningful names to help you remember what kind of values they store.)
Taking this a step further, since these are property names, they are likely to be used in getProperty calls. So why not rename the class PropertyUtils or ConfigUtils, and have matching static methods which use the property names. Then you can add default property values if certain properties are optional.
public static final String DB_HOST = "db.host";
public static final String DB_USER = "db.user";
public static final String DB_PWD = "db.pwd";
public static String getDbHost(Properties props)
{
return props.getProperty(DB_HOST, "localhost");
}
public static String getDbUser(Properties props)
{
return props.getProperty(DB_USER, "admin");
}
public static String getDbPwd(Properties props)
{
return props.getProperty(DB_PWD);
}

Static ResourceBundle

I am currently making resources for an app that is using ResourceBundle. The thing is, with the current code to dispatch the resources I would need to create an instance of the resource bundle every time I need it and I can guess this is not a good idea, since I would end up loading the resources again and again.
The second solution would be to divide the bundle into many, But I would end up with bundles have only 2-3 strings and like 15 bundles.
My question is:
Is there a way to simple load all the resources in a single static class and access them from there.
I made this little piece of code that seems to work for me but I doubt its quality.
public class StaticBundle
{
private final static ResourceBundle resBundle =
ResourceBundle.getBundle("com.resources");
public final static String STRING_A = resBundle.getString("KEY_A");
public final static String STRING_B = resBundle.getString("KEY_B");
public final static String STRING_C = resBundle.getString("KEY_C");
}
With this I can call StaticBundle.STRING_A and get the value anywhere in the project but since the bundle is initialized at the same time as the class itself... It is highly possible that the program won't have the time to load the proper local from the preferences.
Is there a good way to do this or any other possible solution?
Thank you
If you intend to have only messages for the default locale then what you have is fine.
Alternatively you could let the caller specify which key it needs instead of having constants, like this:
public static String getMessage(String key) {
return resBundle.getString(key);
}
If you like to support multiple locales then the usual approach is to have a Map<Locale, ResourceBundle>Map<Locale, Map<String, String> where you load the resources only once for each locale. In that case your class would have a method where the caller can specify the locale:
public static String getMessage(String key, Locale locale) {
Map<String, String> bundle = bundles.get(locale); // this is the map with all bundles
if (bundle == null) {
// load the bundle for the locale specified
// here you would also need some logic to mark bundles that were not found so
// to avoid continously searching bundles that are not present
// you could even return the message for the default locale if desirable
}
return bundle.get(key);
}
Edit: As correctly pointed out by #JB Nizet (thanks) ResourceBundle already stores a Map. The custom solution I provided in the source example, was about a custom mechanism similar to ResourceBundle that used a Map of Maps to load translations of keys in a property=value format, not only from files but also a database. I have incorrectly thought that we had a Map of ResourceBundle in that solution. The source example is fixed now.
You can create a singleton class:
public class MyResouceBundle extends ResourceBundle {
private static MyResourceBundle instance = new MyResouceBundle();
// private constructor, no one can instantiate this class, only itself
private MyResourceBundle() {
}
public ResourceBundle getInstance() {
return instance;
}
}
Then, everyone will access the same instance of the class with (to get string for KEY_A, for example):
MyResourceBunde.getInstance().get("KEY_A");

Should i store file names in Java Enum or properties file

I want to store file names, which keep on changing as the new files get added. I am looking for a minimum change in server code later when there is a need to support a new 'file' The thought I have is to store them either in properties file or as Java enum, but still thinking which is a better approach.
I am using REST and having 'file type' in the URL.
Example rest url:
hostname/file-content/TYPE
where value of TYPE could be any of these: standardFileNames1,standardFileNames2,randomFileName1,randomFileName2
I have used TYPE to group the files, so as to minimize the change in url when a new file is added. Dont want to have file names in the URL due to security issues.
my thought goes like this:
having as ENUM:
public enum FileType
{
standardFileNames1("Afile_en", "Afile_jp"),
standardFileNames2("Bfile_en","Bfile_jp"),
randomFileName1("xyz"),
randomFileName2("abc"),
...
...
}
having as properties file:
standardFileNames1=Afile_en,Afile_jp
standardFileNames2=Bfile_en,Bfile_jp
randomFileName1=xyz
randomFileName2=abc
I know having this in properties will save build efforts on every change, but still want to know your views to figure out best solution with all considerations.
Thanks!
Akhilesh
I often use property file + enum combination. Here is an example:
public enum Constants {
PROP1,
PROP2;
private static final String PATH = "/constants.properties";
private static final Logger logger = LoggerFactory.getLogger(Constants.class);
private static Properties properties;
private String value;
private void init() {
if (properties == null) {
properties = new Properties();
try {
properties.load(Constants.class.getResourceAsStream(PATH));
}
catch (Exception e) {
logger.error("Unable to load " + PATH + " file from classpath.", e);
System.exit(1);
}
}
value = (String) properties.get(this.toString());
}
public String getValue() {
if (value == null) {
init();
}
return value;
}
}
Now you also need a property file (I ofter place it in src, so it is packaged into JAR), with properties just as you used in enum. For example:
constants.properties:
#This is property file...
PROP1=some text
PROP2=some other text
Now I very often use static import in classes where I want to use my constants:
import static com.some.package.Constants.*;
And an example usage
System.out.println(PROP1);
Source:http://stackoverflow.com/questions/4908973/java-property-file-as-enum
My suggestion is to keep in properties or config file and write a generic code to get the file list and parse in java. So that whenever a new file comes, there will be no change on server side rather you will add an entry to the properties or config file.

Where to initialize a java Properties object?

I inherited an application which uses a java properties file to define configuration parameters such as database name.
There is a class called MyAppProps that looks like this:
public class MyAppProps {
protected static final String PROP_FILENAME = "myapp.properties";
protected static Properties myAppProps = null;
public static final String DATABASE_NAME = "database_name";
public static final String DATABASE_USER = "database_user";
// etc...
protected static void init() throws MyAppException {
try {
Classloader loader = MyAppException.class.getClassLoader();
InputStream is = loader.getResourceAsStream(PROP_FILENAME);
myAppProps = new Properties();
myAppProps.load(is);
} catch (Exception e) {
threw new MyAppException(e.getMessage());
}
}
protected static String getProperty(String name) throws MyAppException {
if (props==null) {
throw new MyAppException("Properties was not initialized properly.");
}
return props.getProperty(name);
}
}
Other classes which need to get property values contain code such as:
String dbname = MyAppProps.getProperty(MyAppProps.DATABASE_NAME);
Of course, before the first call to MyAppProps.getProperty, MyAppProps needs to be initialized like this:
MyAppProps.init();
I don't like the fact that init() needs to be called. Shouldn't the initialization take place in a static initialization block or in a private constructor?
Besides for that, something else seems wrong with the code, and I can't quite put my finger on it. Are properties instances typically wrapped in a customized class? Is there anything else here that is wrong?
If I make my own wrapper class like this; I always prefer to make strongly typed getters for the values, instead of exposing all the inner workings through the static final variables.
private static final String DATABASE_NAME = "database_name"
private static final String DATABASE_USER = "database_user"
public String getDatabaseName(){
return getProperty(MyAppProps.DATABASE_NAME);
}
public String getDatabaseUser(){
return getProperty(MyAppProps.DATABASE_USER);
}
A static initializer looks like this;
static {
init();
}
This being said, I will readily say that I am no big fan of static initializers.
You may consider looking into dependency injection (DI) frameworks like spring or guice, these will let you inject the appropriate value directly into the places you need to use them, instead of going through the indirection of the additional class. A lot of people find that using these frameworks reduces focus on this kind of plumbing code - but only after you've finished the learning curve of the framework. (DI frameworks are quick to learn but take quite some time to master, so this may be a bigger hammer than you really want)
Reasons to use static initializer:
Can't forget to call it
Reasons to use an init() function:
You can pass parameters to it
Easier to handle errors
I've created property wrappers in the past to good effect. For a class like the example, the important thing to ensure is that the properties are truly global, i.e. a singleton really makes sense. With that in mind a custom property class can have type-safe getters. You can also do cool things like variable expansion in your custom getters, e.g.:
myapp.data.path=${myapp.home}/data
Furthermore, in your initializer, you can take advantage of property file overloading:
Load in "myapp.properties" from the classpath
Load in "myapp.user.properties" from the current directory using the Properties override constructor
Finally, load System.getProperties() as a final override
The "user" properties file doesn't go in version control, which is nice. It avoids the problem of people customizing the properties file and accidentally checking it in with hard-coded paths, etc.
Good times.
You can use either, a static block or a constructor. The only advice I have is to use ResourceBundle, instead. That might better suit your requirement. For more please follow the link below.
Edit:
ResourceBundles vs Properties
The problem with static methods and classes is that you can't override them for test doubles. That makes unit testing much harder. I have all variables declared final and initialized in the constructor. Whatever is needed is passed in as parameters to the constructor (dependency injection). That way you can substitute test doubles for some of the parameters during unit tests.
For example:
public class MyAppProps {
protected static final String PROP_FILENAME = "myapp.properties";
protected Properties props = null;
public String DATABASE_NAME = "database_name";
public String DATABASE_USER = "database_user";
// etc...
public MyAppProps(InputStream is) throws MyAppException {
try {
props = new Properties();
props.load(is);
} catch (Exception e) {
threw new MyAppException(e.getMessage());
}
}
public String getProperty(String name) {
return props.getProperty(name);
}
// Need this function static so
// client objects can load the
// file before an instance of this class is created.
public static String getFileName() {
return PROP_FILENAME;
}
}
Now, call it from production code like this:
String fileName = MyAppProps.getFileName();
Classloader loader = MyAppException.class.getClassLoader();
InputStream is = loader.getResourceAsStream(fileName);
MyAppProps p = new MyAppProps(is);
The dependency injection is when you include the input stream in the constructor parameters. While this is slightly more of a pain than just using the static class / Singleton, things go from impossible to simple when doing unit tests.
For unit testing, it might go something like:
#Test
public void testStuff() {
// Setup
InputStringTestDouble isTD = new InputStreamTestDouble();
MyAppProps instance = new MyAppProps(isTD);
// Exercise
int actualNum = instance.getProperty("foo");
// Verify
int expectedNum = 42;
assertEquals("MyAppProps didn't get the right number!", expectedNum, actualNum);
}
The dependency injection made it really easy to substitute a test double for the input stream. Now, just load whatever stuff you want into the test double before giving it to the MyAppProps constructor. This way you can test how the properties are loaded very easily.

Categories