I've got a "normal" Java PropertyResourceBundle that's based on a stack of .properties files. In a few places, it would be much more convenient to operate on a Properties object based on the correct translated .properties file instead of the ResourceBundle. Is there a convient way to "cast" the ResourceBundle to a Properties?
What'd I'd like is something like this:
Locale currentLocale = MagicLocaleFactory.getLocale();
ResourceBundle myResources = ResourceBundle.getBundle("MyResources", currentLocale);
Properties myProperties = myResources.magicallyProduceAPropertiesObject();
So afterwords, the myProperties object behaves as if it had been instantiated from the same .properties file that ResourceBundle.getBundle() went and found.
There are a few ways to do this "by hand"; for example, iterating though the set of key-value pairs of the ResourceBundle and installing them in a fresh Properties object, but I was hoping there was a better, or at least shorter, way to do it.
Edit:
To answer the obvious "but, WHY?" question, the case is this: we're retrofitting a long-existing desktop java program for i18n. The program is already pulling strings from a Properties object backed by a single .properties file. We're replacing the single file with multiple files and "promoting" the Properties object to a resource bundle. The problem, such as it is, is that the method to get a key on Properties is getProperty, whereas for ResourceBundle it's getString or getObject. Changing where the Properties object comes from before it gets passed around the program and has strings pulled out is very easy. Changing the actual method call is... less easy. Sure, you can pretty much search and replace for that, but then instead of just changing the one class that loads the properties, we have to touch, essentially, every single source file. (Yeah, there's a lot of text in this thing.) We were hoping we had missed a way to to use the ResourceBundle's multiple .properties with fallback mechanism without having to rewire the entire app. (Gratuitous Gandalf quote: "There never was much hope. Just a fool's hope.")
There is no built-in way to do what you want, but as you said, it isn't difficult to do it yourself: the basically have the same interface, and copying the keys and values from the bundle to the properties is easy.
There is a caveat, though. Although the interface is similar, the implementation is not: the resource bundle has an inheritance model which allows returning the value in foo.properties if it isn't defined in foo_fr_FR.properties and foo_fr.properties. So copying all the entries won't get you the same properties as it they had been loaded from the properties file. It will get the entries of the properties file and the properties of all its parents. But I guess you knew that since you're talking about a stack of properties files.
You haven't stated why you would prefer a Properties over a ResourceBundle, so it's hard to give you a better answer.
Another solution would be to simply load the properties yourself:
Properties props = new Properties();
properties.load(MyClass.class.getResourceAsStream("MyResources_" + locale + ".properties")
This way, you would get only the entries from the specific properties file.
There in none and for the good reason: ResourceBundle is meant to contain properties in different languages, so that it would load *and fall-back appropriate file – when you ask for let's say messages with de-AT locale (German, Austria), it will fall-back to German if it is able to find one or to your base properties file (messages.properties) in other case.
I don't really know what is your use case here (maybe it is simply achievable in a different way?) but it seems that the only way is to read directly from properties file and unfortunately imitate the mechanism I mentioned above (the tricky part are Portuguese Brazil and Chinese Traditional which should not fall back to their "default" languages ("pt" and "zh" respectively)).
Another solution is iterate on keys and puts all pair in a properties object, You can use convertBundleToProperties:
static Properties convertBundleToProperties(ResourceBundle resource) {
Properties properties = new Properties();
Enumeration<String> keys = resource.getKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
properties.put(key, resource.getString(key));
}
return properties;
}
Related
In java, we set system properties with System.SetProperties(Key, Value). I have the following queries related to it.
On what occasion we set the system properties in our code?
How do we determine the Key? i.e. How we will know what exact string we should give for Key?
Your question is so generic that any answer will be vague. You will probably get much better answers if you can be more specific.
On what occasion we set the system properties in our code?
This is like asking "when should we use the + operator". The answer, not too surprisingly, is "only when you need to".
System properties let you configure parts of the Java runtime (or your application server, etc) to do things differently. When you find an issue and it turns out the correct solution to the problem is to configure the Java runtime to modify its behaviour, that's when you need to find whether there is a system property. If there is, you need to set it to a value that gets you the behaviour your want.
How do we determine the Key? i.e. How we will know what exact string we should give for Key?
Through documentation, really. Lets say you run into a problem whre foo.bar() doesn't do what you think it would. Or it breaks in a case that's important to you. You should read the documentation for foo.bar(). It might say that you can change the behaviour by setting a system property. Then you set that system property to the value mentioned in the documentation.
Watch out: some system properties can not be set at all. Or rather, you can set them, but changing them after your program has started (main(string[]) has been called) has no effect.
I have this little snippet I use to see all the currently set system properties and their values. Helps with exploration and getting some ideas:
final String SEPARATOR = "=";
Properties properties = System.getProperties();
for (Object property : properties.keySet()) {
String prop = (String) property;
System.out.println(prop + SEPARATOR + properties.getProperty(prop));
}
You almost never set system properties. One use case is test automation: if the system under test behaves differently based on system properties, it makes sense to set them in the code that sets up the test environment. In regular application code you don't see it happen often.
If you're creating properties of your own, you can use anything you want as the key. Most people use the name of their project as the namespace so that the properties they use won't conflict with properties from libraries or other projects. This means the keys will have the form myproject.myproperty.
What's the correct way to access the Properties() object after loading it with a .properties file?
One way I've used in the past is to just store each Properties object in a static variable in a utility class and access it through there. However I've been thinking that it might be better to actually create a wrapper class with some utility functions? Not sure if that would be helpful. Most examples I've found just concern themselves with how one loads a properties file but not what should happen after that.
Is there a generally approved way to do it and what are its pros and cons?
Just like Rob Conklin said, it's probably good to keep a level of abstraction in order to (in the future) be able to switch out the properties-file based storage.
However, you can set merge your properties with System.getProperty() to get easy access from wherever in your program
FileInputStream propFile = new FileInputStream("myProperties.properties");
Properties p = new Properties(System.getProperties());
p.load(propFile);
// set the system properties
System.setProperties(p);
Whichever properties you set latest will override the others (if the names collides)
You can then later access the property simply with
System.getProperty("propName");
Do yourself a huge favor, and create a DAO around your properties file access. In most systems I've worked on, we always wished we had this abstraction, it allows properties files to become database driven at some future point.
You can cache it inside the DAO as a static variable, but that becomes hidden from the client.
I have been looking over these three sites on how to create a map lookup (or any other lookup for that matter) using log4j2:
http://logging.apache.org/log4j/2.x/manual/extending.html#Lookups
http://logging.apache.org/log4j/2.x/manual/lookups.html
http://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution
I understand the general idea behind what I am reading, I am just having a difficult time putting all the bits and pieces together.
Goal
To be able to place a variable, of some sort, in a log4j2.xml file that at configuration time, or runtime, replaces that variable with the values in a resource bundle. This is what i have so far:
Configuration File
Lookup Class
The getValue(key) method looks in a resource bundle for the email values associated with that key.The #Plugin name is "map" which, if i have read correctly, is related to prefixes in the .xml file that are also "map". So, wouldn't "error.notification.emails" get passed into the lookup(String key) method in the MapPropertiesLookup class? What do i need to do in order to get this to work?
Yes, map is the name of the lookup you are creating. Since Log4j already has a Lookup named map creating another is going to cause problems.
Yes, error.notification.emails should be passed as the key value to the Lookup. Assuming that getValue(key) works your lookup would probably work if it was named something else.
However, it might make more sense for you to file a Jira and ask for a ResourceBundleLookup where the syntax could be something like: ${bundle:bundleName:key}. Of course, "bundleName:key" would be passed to the lookup as the key and it would split the key into the component parts.
If you have further problems you might consider asking on the Log4j developers mailing list.
I added a new lookup for the next release (whether it is a beta or release candidate):
Committed revision 1531064.
You can use it now if you build Log4J from source. The format is documented if you build the site, it is used as follows:
${bundle:BundleName:BundleKey}
For example:
${bundle:com.domain.Messages:MyKey}
The java.util.ResourceBundle class will look for com/domain/Messages.properties on the classpath.
Our JIRA issue: https://issues.apache.org/jira/browse/LOG4J2-420
I'm at the point in my first real application where I am adding in the user settings. I'm using Java and being very OO (and trying to keep it that way) so here are my ideas:
Load everything in the main() and
pass it all 'down the line' to the
required objects (array)
Same as above, but just pass the
object that contains the data down
the line
Load each individual setting as
needed within the various classes.
I understand some of the basic pros and cons to each method (i.e. time vs. size) but I'm looking for some outside input as to what practices they've successfully used in the past.
Someone should stand up for the purported Java standard, the Preferences API... and it's most recent incarnation in JDK6. Edited to add, since the author seems to savvy XML, this is more appropriate than before. Thought I believe you can work XML juju with Properties too, should the spirit take you.
Related on SO: Preferences API vs. Apache solution, Is a master preferences class a good idea?
(well, that's about all the standing up I'm willing to do.)
Use a SettingsManager class or something similar that is used to abstract getting all settings data. At each point in the code where you need a setting you query the SettingsManager class - something like:
int timeout = SettingsManager.GetSetting("TimeoutSetting");
You then delegate all of the logic for how settings are fetched to this single manager class, whose implementation you can change / optimize as needed. For instance, you could implement the SettingsManager to fetch settings from a config file, or a database, or some other data store, periodically refresh the settings, handle caching of settings that are expensive to retrieve, etc. The code using the settings remains blissfully unaware of all of these implementaton decisions.
For maximum flexibility you can use an interface instead of an actual class, and have different setting managers implement the interface: you can swap them in and out as needed at some central point without having to change the underlying code at all.
In .NET there is a fairly rich set of existing configuration classes (in the System.Configuration) namespace that provide this sort of thing, and it works out quite well.
I'm not sure of the Java equivalent, but it's a good pattern.
Since configuration / settings are typically loaded once (at startup; or maybe a few times during the program's runtime. In any way, we're not talking about a very frequent / time-consuming process), I would prefer simplicity over efficiency.
That rules out option number (3). Configuration-loading will be scattered all over the place.
I'm not entirely sure what the difference is between (1) and (2) in your list. Does (1) mean "passing discreet parameters" and (2) mean "passing an object containing the entire configuration"? If so, I'd prefer (2) over (1).
The rule of thumb here is that you should keep things simple and concentrated. The advantage of reading configuration in one place is that it gives you better control in case the source of the configuration changes at some point.
Here is a tutorial on the Properties class. From the Javadocs (Properties):
The Properties class represents a
persistent set of properties. The
Properties can be saved to a stream or
loaded from a stream. Each key and its
corresponding value in the property
list is a string.
A property list can contain another
property list as its "defaults"; this
second property list is searched if
the property key is not found in the
original property list.
The tutorial gives the following example instantiation for a typical usage:
. . .
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();
// create application properties with default
Properties applicationProps = new Properties(defaultProps);
// now load properties from last invocation
in = new FileInputStream("appProperties");
applicationProps.load(in);
in.close();
. . .
You could, of course, also roll your own system fairly directly using a file-based store and an XML or YAML parser. Good luck!
We have recently started using JSR-330 dependency injection (using Guice from SVN) and found that it was possible to read in a Properties file (or any other map) and bind it inside Guice in the module in the startup code so that the
#Inject #Named("key") String value
string was injected with the value corresponding to the key when that particular code was called. This is the most elegant way I have ever seen for solving this problem!
You do not have to haul configuration objects around your code or sprinkle all kinds of magic method calls in each and every corner of the code to get the values - you just mention to Guice you need it, and it is there.
Note: I've had a look at Guice, Weld (Seam-based) and Spring which all provide injection, because we want JSR-330 in our own code, and I like Guice the best currently. I think the reason is because Guice is the clearest in its bindings as opposed to the under-the-hood magic happening with Weld.
I started to work in translating a Java program which has tens of dialog classes to deal with. I wonder how is it possible to create a parameter that is understood in all of those classes, without having to declare it in each one.
Actualy are two parameters. Tried with something like:
public Locale currentLocale = new Locale("en");
public ResourceBundle text = ResourceBundle.getBundle("MessagesBundle", currentLocale);
in the launching class of the program but had no luck.
Any tip?
without having to declare it in each one.
There are two general approaches:
Singleton pattern.
Store the reference in the thread using ThreadLocal.
Either way, you need to take a lot of caveats into account. Singletons doesn't work well in environments with multiple classloaders/JVM's and ThreadLocals doesn't work well when you spawn multiple threads yourself to process the business task. You need to understand those caveats very well before continuing.
The safe approach would be to create the object only once during application's startup in some front controller class and pass it as argument into the business/model objects whenever needed.
Set a Parent ResourceBundle
Use the ResourceBundle.setParent() method. If a specific key cannot be found in the current ResourceBundle it will search the parent ResourceBundle.
getBundle will automatically search for parents
As the JavaDoc for ResourceBundle.getBundle(String, Locale, ClassLoader) states, this automatically happens when you load a resource bundle for a specific Locale and a bundle with the same base name can be found without the locale suffix.
In your example the ResourceBundle will be loaded from a file (.properties extension is optional) named:
MessagesBundle_en.properties
But it will also look for a generic
MessagesBundle.properties
and set this as the parent. If you provide this generic file as well, it will be used as a default whenever a key in a specific locale bundle cannot be found.