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)
Related
I have a java web application that needs to read information from an external file when initialized (ie: when jboss server is started).
Since reading and parsing this text file is an expensive operation, we decided to load it only one time and then set it to memory so it can be accessed anywhere (the variable doesn't need to be modified after initialitazion).
I've read everywhere that global variables should be avoided, so what is the best practice for this scenario?
Edit: I should have mentioned that the information should be stored in a simple List variable.
it strongly depends on the framework you are using. In general you are right, global variables are often treated as anti-pattern. But you have to understand the reason, which is mainly testability.
To get "global" things tested you usually use patterns like Factories, Provider often in combination with dependency injection (e.g. Spring, Guide).
In the end you are caching. For caching you can also use some framework like EHCache. But maybe that's to much overhead for you.
To keep it simple and in plain Java I would suggest something like this (just first draft, not tested):
public class FileCache {
Map<String, String> fileContents = new HashMap<String, String>();
public void loadFile(String path) {
if (fileContents.contains(path)) {
return fileContents.get(path);
}
// Loading logic
String content = loadContentOfFile(path);
fileContents.put(path, content);
return content;
}
}
With this you keep your caching a bit scalable (you can cache as many files as you want) and it will be easy to test this class. But in the end you end up with some global place where you need to access this class.
And then you either have Dependency Injection, a static variable or some Singleton.
With a singleton you should care to keep it simple, since it's again hard to test.
public class FileContentProvider {
private static FileContentProvider instance;
private final FileCache fileCache = new FileCache();
public static FileContentProvider getInstance() {
if (instance == null) {
instance = new FileContentProvider();
}
return instance;
}
public FileCache getFileCache() {
return fileCache;
}
}
A static Configuration-Object that is global accessible is pretty common. You could use a Singleton-Pattern to access the Config. That could look like this:
public class Config {
private static Config myInstance;
private Config() {
// Load the properties
}
public static getInstance() {
if (myInstance == null) {
myInstance = new Config();
}
return myInstance;
}
public String getConfigPropertyBla()
...
}
If you use Spring you could let Spring load the properties to a Bean. You can then access the Bean via autowiring everywhere in your application. I personally think, that this is a very nice solution.
DI, IoC container. Have a look at Guice, very nice thing.
My Android app uses an enum type to define certain API endpoints.
public static enum API_ENDPOINT{
MISSION, FEATURED_MEDIA
}
The enum type seems an appropriate argument for methods that are dependent on the API call type, but I'm unable to translate enums to consistent Strings (i.e for mapping to API endpoint urls) across devices configured with different languages.
In Turkish API_ENDPOINT.values() returns: mıssıon, featured_medıa
In English API_ENDPOINT.values() returns: mission, featured_media
An obvious solution is an additional data structure that maps API_ENDPOINT to hard-coded string endpoints, but I'm curious as to whether this behavior of enum.values() is intended and/or avoidable.
Solved: Thanks everyone for the insight. It turns out deeper in the logic to convert API_ENDPOINT to a URL string I used String.toLowerCase() without specifying a Locale, which resulted in the undesirable behavior. This has been replaced with String.toLowerCase(Locale.US)
You can hard-code the strings as part of the enum, without any additional data structure:
public static enum API_ENDPOINT{
MISSION("mission"), FEATURED_MEDIA("featured_media");
private final String value;
API_ENDPOINT(String value) { this.value = value; }
public String value() { return value; }
}
but it would be nice if there were just a way to control the representation that's automatically generated.
The JLS enum section doesn't speak directly to language differences like this, but strongly suggests that the output would exactly match the enum identifiers; I'm surprised that you'd even get lower-case strings with upper-case identifiers.
After further testing, this isn't reproducible, something else must be going on in your code.
This minimal program displays the enum identifiers exactly as typed regardless of locale:
public class MainActivity extends Activity {
public enum ENUM {
MISSION, FEATURED_MEDIA
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.text);
String enums = "";
for (ENUM e : ENUM.values()) {
enums += e + " ";
}
textView.setText(enums);
}
}
You can define two property-files. One for English and one for Turkish.The Enum could then look like this:
public static enum API_ENDPOINT{
MISSION("path.to.property.mission"), FEATURED_MEDIA("path.to.property.featured_media");
private String propertyName;
API_ENDPOINT(String propertyName){
this.propertyName = propertyName;
}
// language could also be an enum which defines the language to be taken
// and should contain the path to the file.
public String getTranslatedText(Language language){
Properties prop = new Properties();
try {
//load a properties file from class path
prop.load(API_ENDPOINT.class.getClassLoader().getResourceAsStream(language.getPropertyFileName()));
//get the translated value and raturn it.
return prop.getProperty(propertyName);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
The Property-File will look like this (English):
path.to.property.mission=Mission
path.to.property.featured_media=Featured Media
Same goes for Turkish.
Hope that helps.
EDIT: Due to you are using Android, this might be the solution for your problem:
Is there a sensible way to refer to application resources (R.string...) in static initializers
Make Enum.toString() localized
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");
First, I have to admit my problem is similar to Singleton with Arguments in Java
I read it, but the solution doesn't work for me. I know the factory pattern is the best solution to that problem.
Here is my problem.
I create a "singleton" class to provide some common function, for example get a global configuration parameter. This class need a handler to access the system resources, for example read the configuration file. Cause this class just act as a lib, the handler must pass in from outside, and the Handler is a system class.
So, I write my code in this way:
public class SingletonGlobalParameters {
private static final SingletonGlobalParameters instance = new SingletonGlobalParameters ();
private boolean initial = false;
private String aParameter = null;
private SingletonGlobalParameters () { }
public static SingletonGlobalParameters getInstance() {
if (initial == false) {
throw exception...
}
return instance;
}
public void init(Handler h) {
if (initial == false) {
Handler fileHandler = h;
aParameter = fileHandler.read(); // something like this
initial = true;
}
}
public int getParameter() {
return aParameter;
}
}
I remove synchronization stuff to make question clear.
This implement looks ugly, right? The class must guarantee to initialize before use.
Any good ideas? Thanks very much, this problem has troubled me for some time.
OK! I give the real world problem. This is a Android problem.
public class Configuration {
private static final Configuration instance = new Configuration ();
private boolean initial = false;
private long timeStamp = -1;
private Configuration () { }
public static Configuration getInstance() {
if (initial == false) {
throw exception...
}
return instance;
}
public void load(Context context) {
if (initial == false) {
SharedPreferences loader = context.getSharedPreferences("Conf", Context.MODE_PRIVATE);
timeStamp = loader.getInt("TimeStamp", 0);
initial = true;
}
}
public int getTimeStamp() {
return timeStamp;
}
}
Is this make question clearer?
The right pattern is the one allowing you to do things you need. Do not be so dogmatic. Singleton with a parameter is widely used and acepted in android environment (parameter is usually context). But in plain java environment, dependency injection would be better as it
decouples code using you singleton from the fact it is singleton, and modalities of its creation. There are a plenty of DI frameworks,like picocontainer, spring, google guice - just pick your favorite
EDIT: When I wrote this answer, the question had no context - we didn't know it was an Android app. It may be that it's not a bad solution in this case; but I would at least think about other approaches. I'm leaving my answer below for the more general case.
I would attempt to move away from the singleton pattern to start with.
Why is each configuration parameter needed from many places? Could you encapsulate each aspect of configuration (possibly multiple parameters in a single aspect in some cases) and then use dependency injection (e.g. with Guice) to make those encapsulated versions available to the components that need them?
It's hard to give concrete advice when we really don't know what kind of app you're writing, but in general it's a good idea to move away from global state, and dependency injection often provides a clean way of doing this. It's not a panacea, and it could be that in some cases you can redesign in a different way, but it would be my first thought.
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.