Does anyone know of a method to load a properties file, and dynamically create Strings with identical names to the key value?
I'm trying to clean up my code by moving all the system messages etc out of the logic and into a properties file, but want to avoid having to have a class consisting of dozens of lines like the following:
final String COMMS_ERROR = properties.getProperty(COMMS_ERROR);
An example of what I'm trying to achieve:
for (String key : properties.getPropertyValues()) {
final String <key> = properties.getProperty(key)
}
Obviously this won't work, the compiler will throw a fit. But I'm wondering if there's an elegant solution to do the same thing - create new Strings using the key names from the properties file - be it via a separate library or in my own code.
One solution I've thought of is to populate a HashMap with the keys/values from the properties file, but then that would mean less elegant code in the form of:
import com.x.y.messages;
...
throw new Exception(HM.get("COMMS_ERROR"));
Where HM is the HashMap located within com.x.y.messages...
Ideally I just want to be able to do:
import com.x.y.messages;
....
throw new Exception(COMMS_ERROR);
Any thoughts/advice appreciated.
If those properties can change after compilation (if not, then why would they be used) you'd not have any chance to create AND use those strings dynamically. Sure, there are ways to dynamically create code (like AOP runtime weaving) but that code would not be usable in the normal compilation process.
So how would the compiler know that COMMS_ERROR actually exists in this line throw new Exception(COMMS_ERROR);? It can't and thus you'd need to go for the HashMap approach. Note that Properties is actually a Map<String, String> (ok, it is a Hashtable<Object, Object> as of Java 6 but it acts like a Map<String, String>), thus there's no need to create a new one.
Edit: what you could do is use static imports like this:
package yourpackage;
public class Props
{
private static Properties props;
public static String prop(String prop)
{
return props.getProperty( prop );
}
}
Use it like this:
import static yourpackage.Props.prop;
....
prop("someKey");
Note that static import has its drawbacks like looking as if the methods were part of the class it uses, so I'd just like to provide an alternative and let you decide whether to use it or not.
What is wrong with
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources( "com/x/y/message.properties" );
while( resources.hasMoreElements() ) {
URL url = resources.nextElement();
Properties p = new Properties();
p.load( url.openStream() );
...
}
i dont see why store data from Properties to HashMap
import com.x.y.messages;
....
throw new Exception(p.getProperty("COMMS_ERROR"));
You cannot declare local variables on the fly but you can use a map:
Map<String, String> messages = new HashMap<String, String>();
for (String key : properties.getPropertyValues()) {
messages.put(key, properties.getProperty(key));
}
to use them:
throw new Exception( messages.get( "KEY" ) )
See http://download.oracle.com/javase/6/docs/api/java/util/Map.html
But in fact as Thomas pointed out above you don't need a new HashMap just
throw new Exception( properties.getProperties(key) );
I have previously written helper classes myself that kept a Properties file in sync with a Constants class. But that only works if you stick to conventions.
Lets say you have a class like this:
public final class Constants{
private Constants(){}
public static final String SOME_PROPERTY_NAME = "some.property.name";
public static final String THIS_ONE_NOT_SET_YET = null;
public static final String PROPERTY_NOT_DEFINED = "property.not.defined";
}
and a property file like this:
some.property.name=Hello World
no.constant.for.this.yet=Hello again
What my helper class would do was to loop over all properties and all constants, make matches and identify those that didn't correspond to anything.
So in this case:
a)
In Constants.java,
public static final String THIS_ONE_NOT_SET_YET = null;
would be changed to
public static final String THIS_ONE_NOT_SET_YET = "this.one.not.set.yet";
and in the properties file, this line would be introduced:
this.one.not.set.yet=
b)
in the properties file, this line would be added
property.not.defined=
c)
In Constants.java, this line would be added:
public static final String NO_CONSTANT_FOR_THIS_YET = "no.constant.for.this.yet";
It's not perfect, but that way you get pseudo-compile-time safety. You compile against constants, and your helper keeps those constants in sync with he properties.
Obviously this approach gets a lot more complicated if you have more advanced scenarios.
E.g.
Properties starting with "foo." being stored in "foo.properties" while properties named "bar." are being stored in "bar.properties"
Internationalization: Now you have foo.properties, foo.properties.es, foo.properties.de etc. Keeping that in sync is a major nuissance.
Perhaps one thing to consider would be to have your constants class dynamically created from one or more properties files during the build process. Your code generator (a Main class, a Groovy script or even a shell script) would basically just have to do this (pseudocode):
properties = readProperties()
writeClassHeader()
for prop : properties
writeln "public static final String "
+ prop.name.upperCase().replace(".","_") + "= \"" + prop.name + "\";"
writeClassFooter()
I'm not aware of a tool that would do this, and it doesn't fit the normal Java way of doing things. (In Java you can't add new variables on the fly ... unlike Javascript for example.)
It is theoretically possible to implement something along these lines, but it would probably entail generating and compiling a class for each kind of property file, and recompiling the rest of your code against these classes APIs. Unless you've got huge numbers of these property files, it is easier to code the classes by hand. (And if you do have huge numbers of these properties files, I would be inclined to see if there was a better way to handle the information in those files.)
Yeah that's what I was hoping for - a library that would contain the necessary magic
Unfortunately no ordinary library could do this. The generation / recompilation has to happen at build time. (A library could generate the classes at runtime and even compile and load them. But getting it to recompile the rest of your application at runtime is at best difficult, and typically impossible ... because the source code is not available.)
It looks almost exactly what my library does! Check it out: http://owner.aeonbits.org
Example:
# Properties file (call it the same name as the Java class and put
# it in the same package
port=80
hostname=foobar.com
maxThreads=100
//properties mapper interface
public interface ServerConfig extends Config {
int port();
String hostname();
int maxThreads();
}
// how you use it:
ServerConfig cfg = ConfigFactory.create(ServerConfig.class);
System.out.println("Server " + cfg.hostname() + ":" + cfg.port() + " will run " + cfg.maxThreads());
But, you can do much more with OWNER library.
Related
I have simple problem and want advice how to improve the design I will try not to give details of my implementation but to be more abstract.
I have a configuration file with xml structure.(but can be changed)
<configurations>
<conf>
<path1></path1>
<path2></path2>
<conf>
<conf>
<path1></path1>
<path2></path2>
<conf>
</configurations>
where path1 and 2 are paths to some files which are needed in the business logic where I do repeatable actions with this paths many times(like banchmarks)
Then using this paths I need to do some operations but the content of every conf is separated from one another they can run in parallel without problems.
So first I read the configuration and store them in a List and then iterate over the list and execute consecutively the business logic.
I am wondering how can I improve the design of my decision?
I think I can use Iterator patter to iterate over the structure and to accomplished the repeatable logic for every cong to use the Strategy pattern.
Am wondering how to separate logic to use different runners for operations in every conf tag?
I think in many things that could be change for your implementation.
It's important to take the parts that vary and encapsulate them, by this way, later, you can alter or extend the parts that vary without affecting
those that don’t.
The parts that I suppose that could change are :
The source of your conf, it could come from a file (XML, CSV, XLSX, Properties File ...), your data base, etc.
The configuration. New attributes could be added to one conf.
Maybe you don't go to use all the configurations, so I vote for load some configuration when you need this one.
If one business logic needs one conf from your xml file and another business logic needs one conf from your csv file, your flexibility is not the best.
I propose the use of an utility class with the methods that you need to create/load your configuration from different sources.
I suppose that each conf has a name or an id. You could also add more properties as the list of path, the source type, etc.
A map is a better option to store your configurations. You could use a key as (confName, SourceType).
You could use MultiKey from (apache.commons) to create the key of your map.
Ex:
Multikey key = new Multikey(confName, sourceType);
You could create an enum for the source types:
public enum SourceType {
XML,
HTML,
CSV,
ORACLE_DB,
PROPERTIES;
}
Create one Singleton as utility class to create and load your configurations.(I recommend you to read the section of "Singleton" in the book Effective Java)
public enum ConfigurationLoader {
INSTANCE;
private Map<Multikey<String, SourceType>, Configuration> configurations = new HashMap<>();
public Configuration getConfiguration(String confName, SourceType sourceType) {
Multikey<String, SourceType> key = new Multikey<>(confName, sourceType);
if (!isConfigurationLoaded(key)) {
loadConfiguration(confName, sourceType);
}
return configurations.get(key);
}
//helper meethod to know if the configuration has been loaded
private boolean isConfigurationLoaded(Multikey<String, SourceType> key) {
return configurations.get(key) != null;
}
private void loadConfiguration(String confName, SourceType sourceType) {
if (SourceType.XML == sourceType) {
loadConfigurationFromXml(confName);
return;
}
if (SourceType.CSV == sourceType) {
loadConfigurationFromCSV(confName);
return;
}
if (SourceType.ORACLE_DB == sourceType) {
loadConfigurationFromOracleDb(confName);
return;
}
}
private void loadConfigurationFromXml(String confName) {
//your imlementation to create the configuration from XML file
// at the end you put the conf in the map
//.....
//configurations.put(key, configuration);
}
//Equals for the others methods
//private Configuration loadConfigurationFromCsv(String confName) { ....}
//private Configuration loadConfFromDb(String confName){...}
}
The Configuration class (I think that you need only this class, you go to have only fields to add and not behaviors):
public class Configuration {
private String name;
private SourceType sourceType;
private List<String> paths = new ArrayList<String>();
public Configuration(String name, SourceType sourceType) {
super();
this.name = name;
this.sourceType = sourceType;
}
public void addPath(String path) {
paths.add(path);
}
public List<String> getPaths() {
return paths;
}
}
You need to know the configuration that you want,so in your business layer, you could call your configuration as:
Configuration configuration = ConfigurationLoader.INSTANCE.getConfiguration(confName, SourceType.XML);
Next step, create your threads and iterate over you business logic with your configuration...
Hm, sounds a bit like you are desparately trying to apply design patterns to everything :)
(Which is actually not a bad thing as long as your main goal is to learn about patterns.)
As for the Iterator pattern, ok, you store your data in a list and somehow iterate over it. I would not call this applying the Iterator pattern. Iterators are already defined for most containers of the standard library. In most cases you do not directly use these. It is much more convenient to use an enhanced for loop or Java 8 streams, which can also automatically parallelize the iteration.
As for the Strategy pattern, this would be useful if you need to implement the logic of the different configurations in different classes. But as long as you only want to use different paths, this is probably overkill.
Let us assume up to runtime we do not know what are the details of configuration(may user need to configure these parameters in config file before running the application.
I want to read those configuration details and need to reuse them wherever I need them in my application. For that I want to make them as global constants(public static final).
So, My doubt is, is there any performance implications if I read from config file directly from the required class? since,runtime values I can not directly put in separate Interface.
I am thinking it will impact performance.Please suggest me any better way to do this.
UPDATE: Can I use separate final class for configuration details?
putting all configuration details as constants in a separate public final class
(To read all configuration details at once from the configuration file and storing them as global constants for later use in application)
I am thinking it will impact performance.
I doubt that this will be true.
Assuming that the application reads the configuration file just once at startup, the time taken to read the file is probably irrelevant to your application's overall performance. Indeed, the longer the application runs, the less important startup time will be.
Standard advice is to only optimize for application performance when you have concrete evidence (i.e. measurements) to say that performance is a significant issue. Then, only optimize those parts of your code that profiling tells you are really a performance bottleneck.
Can I use separate final class for configuration details
Yes it is possible to do that. Nobody is going to stop you1.
However, it is a bad idea. Anything that means that you need to recompile your code to change configuration parameters is a bad idea. IMO.
To read all configuration details at once from the configuration file and storing them as global constants for later use in application.
Ah ... so you actually want to read the values of the "constants" instead of hard-wiring them.
Yes, that is possible. And it makes more sense than hard-wiring configuration parameters into the code. But it is still not a good idea (IMO).
Why? Well lets look at what the code has to look like:
public final class Config {
public static final int CONST_1;
public static final String CONST_2;
static {
int c1;
String c2;
try (Scanner s = new Scanner(new File("config.txt"))) {
c1 = s.nextInt();
c2 = s.next();
} catch (IOException ex) {
throw RuntimeException("Cannot load config properties", ex);
}
CONST_1 = c1;
CONST_2 = c2;
}
}
First observation is that makes no difference that the class is final. It is declaring the fields as final that makes them constant. (Declaring the class as final prevents subclassing, but that has no impact on the static fields. Static fields are not affected by inheritance.)
Next observation is that this code is fragile in a number of respects:
If something goes wrong in the static initializer block. the unchecked exception that is thrown by the block will get wrapped as an ExceptionInInitializerError (yes ... it is an Error!!), and the Config class will be marked as erroneous.
If that happens, there is no realistic hope of recovering, and it possibly even a bad idea to try and diagnose the Error.
The code above gets executed when the Config class is initialized, but determining when that happens can be tricky.
If the configuration filename is a parameter, then you have the problem of getting hold of the parameter value ... before the static initialization is triggered.
Next, the code is pretty messy compared with loading the state into a instance variables. And that messiness is largely a result of having to work within the constraints of static initializers. Here's what the code looks like if you use final instance variables instead.
public final class Config {
public final int CONST_1;
public final String CONST_2;
public Config(File file) throws IOException {
try (Scanner s = new Scanner(file)) {
CONST_1 = s.nextInt();
CONST_2 = s.next();
}
}
}
Finally, the performance benefits of static final fields over final fields are tiny:
probably one or two machine instructions each time you access one of the constants,
possibly nothing at all if the JIT compiler is smart, and you handle the singleton Config reference appropriately.
In either case, in the vast majority of cases the benefits will be insignificant.
1 - OK ... if your code is code-reviewed, then someone will probably stop you.
Have you ever heard of apache commons configuration http://commons.apache.org/proper/commons-configuration/ ?
It is the best configuration reader I have ever found and even am using it in my application which is running in production since 1 year. Never found any issues, very easy to understand and use, great performance. I know its a bit of dependency to your application but trust me you will like it.
All you need to do is
Configuration config = new ConfigSelector().getPropertiesConfiguration(configFilePath);
String value = config.getString("key");
int value1 = config.getInt("key1");
String[] value2 = config.getStringArray("key2");
List<Object> value3 = config.getList("key3");
And thats it. Your config object will hold all the config values and you can just pass that object to as many classes as you want. With so many available helpful methods you can extract whichever type of key you want.
It will be only one time cost if you are putting them in a property file and reading the file at the start of your application and initialize all the parameters as system parameters(System.setProperty) and then define constants in your code like
public static final String MY_CONST = System.getProperty("my.const");
But ensure the initialization at start of your application before any other class is loaded.
There are different types of configuration.
Usually some sort of bootstrapping configuration, for example to connect to a database or service, is needed to be able to start the application. The J2EE way to specify database connection parameters is via a 'datasource' specified in your container's JNDI registry (Glassfish, JBoss, Websphere, ...). This datasource is then looked up by name in your persistence.xml. In non-J2EE applications it is more common to specify these in a Spring context or even a .properties file. In any case, you usually need something to connect your application to some sort of data store.
After bootstrapping to a data store an option is to manage config values inside this datastore. For example if you have a database you can use a separate table (represented by e.g. a JPA Entity in your application) for configuration values. If you don't want/need this flexibility you can use simple .properties file for this instead. There is good support for .properties files in Java (ResourceBundle) and in frameworks like Spring. The vanilla ResourceBundle just loads the properties once, the Spring helper offers configurable caching and reloading (this helps with the performance aspect which you mentioned). Note: you can also use Properties backed by a data store instead of a file.
Often both approaches coexist in an application. Values that never change within a deployed application (like the application name) can be read from a properties file. Values that might need to be changed by an application maintainer at runtime without redeployment (e.g. the session timeout interval) might better be kept in a reloadable .properties file or in a database. Values that can be changed by users of the application should be kept in the application's data store and usually have an in-application screen to edit them.
So my advise is to separate your configuration settings into categories (e.g. bootstrap, deployment, runtime and application) and select an appropriate mechanism to manage them. This also depends on the scope of your application, i.e. is it a J2EE web app, a desktop app, command-line utility, a batch process?
What kind of configuration file do you have in mind? If it is a properties file, this might suit you:
public class Configuration {
// the configuration file is stored in the root of the class path as a .properties file
private static final String CONFIGURATION_FILE = "/configuration.properties";
private static final Properties properties;
// use static initializer to read the configuration file when the class is loaded
static {
properties = new Properties();
try (InputStream inputStream = Configuration.class.getResourceAsStream(CONFIGURATION_FILE)) {
properties.load(inputStream);
} catch (IOException e) {
throw new RuntimeException("Failed to read file " + CONFIGURATION_FILE, e);
}
}
public static Map<String, String> getConfiguration() {
// ugly workaround to get String as generics
Map temp = properties;
Map<String, String> map = new HashMap<String, String>(temp);
// prevent the returned configuration from being modified
return Collections.unmodifiableMap(map);
}
public static String getConfigurationValue(String key) {
return properties.getProperty(key);
}
// private constructor to prevent initialization
private Configuration() {
}
}
You could also return the Properties object immediately from the getConfiguration() method, but then it could potentially be modified by the code that access it. The Collections.unmodifiableMap() does not make the configuration constant (since the Properties instance gets its values by the load() method after it was created), however since it is wrapped in an unmodifiable map, the configuration cannot be changed by other classes.
Well this is a great problem which is faced in every one's life once in a will. Now coming to the problem, this can be solved by creating a singleton class which has instance variables same as in configuration file with default values. Secondly this class should have a method like getInstance() which reads the properties once and every times returns the same object if it exists. For reading file we can use Environmental variable to get path or something like System.getenv("Config_path");. Reading the properties (readProperties() method) should read each item from config file and set the value to the instance variables of singleton object. So now a single object contains all the configuration parameter's value and also if the parameter is empty than default value is considered.
One more way is to define a class and read the properties file in that class.
This class needs to be at the Application level and can be marked as Singleton.
Marking the class as Singleton will avoid multiple instances to be created.
Putting configuration keys directly to classes is bad: configuration keys will be scattered over the code. Best practice is separation of application code and configuration code. Usually dependency injection framework like spring is used. It loads a configuration file and constructs the objects using configuration values. If you need some configuration value in your class you should create a setter for this value. Spring will set this value during context initialization.
I recommend using JAXB or a similar binding framework that works with text based files. Since a JAXB implementation is part of the JRE, it's pretty easy to use. As Denis I advise against configuration keys.
Here is a simple example for an easy to use and still pretty mighty way to configure you application with XML and JAXB. When you use a DI framework you can just add a similar config object to the DI context.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ApplicationConfig {
private static final JAXBContext CONTEXT;
public static final ApplicationConfig INSTANCE;
// configuration properties with defaults
private int number = 0;
private String text = "default";
#XmlElementWrapper
#XmlElement(name = "text")
private List<String> texts = new ArrayList<>(Arrays.asList("default1", "default2"));
ApplicationConfig() {
}
static {
try {
CONTEXT = JAXBContext.newInstance(ApplicationConfig.class);
} catch (JAXBException ex) {
throw new IllegalStateException("JAXB context for " + ApplicationConfig.class + " unavailable.", ex);
}
File applicationConfigFile = new File(System.getProperty("config", new File(System.getProperty("user.dir"), "config.xml").toString()));
if (applicationConfigFile.exists()) {
INSTANCE = loadConfig(applicationConfigFile);
} else {
INSTANCE = new ApplicationConfig();
}
}
public int getNumber() {
return number;
}
public String getText() {
return text;
}
public List<String> getTexts() {
return Collections.unmodifiableList(texts);
}
public static ApplicationConfig loadConfig(File file) {
try {
return (ApplicationConfig) CONTEXT.createUnmarshaller().unmarshal(file);
} catch (JAXBException ex) {
throw new IllegalArgumentException("Could not load configuration from " + file + ".", ex);
}
}
// usage
public static void main(String[] args) {
System.out.println(ApplicationConfig.INSTANCE.getNumber());
System.out.println(ApplicationConfig.INSTANCE.getText());
System.out.println(ApplicationConfig.INSTANCE.getTexts());
}
}
The configuration file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<applicationConfig>
<number>12</number>
<text>Test</text>
<texts>
<text>Test 1</text>
<text>Test 2</text>
</texts>
</applicationConfig>
protected java.util.Properties loadParams() throws IOException {
// Loads a ResourceBundle and creates Properties from it
Properties prop = new Properties();
URL propertiesFileURL = this.getClass().getResource("/conf/config.properties");
prop.load(new FileInputStream(new File(propertiesFileURL.getPath())));
return prop;
}
Properties prop = loadParams();
String prop1=(String) prop.get("x.y.z");
Given the prevalence of YML to express configuration, I'd recommend creating a YML file with the configuration inside it and then loading that once, at startup, into a POJO, then accessing the fields of that POJO to get the configuration:
user: someuser
password: somepassword
url: jdbc://mysql:3306/MyDatabase
With Java Class
public class Config {
private String user;
private String password;
private String url;
// getters/setters
Jackson can be used to load YML as can SnakeYml directly.
On top of this, you could use the OS project I've been working on - https://github.com/webcompere/lightweight-config - which allows you to wrap this up, and even express placeholders in your file to interpolate environment variables:
user: ${USER}
password: ${PASSWORD}
url: jdbc://${DB_HOST}:3306/MyDatabase
then
Config config = ConfigLoader.loadYmlConfigFromResource("config.yml", Config.class);
Is it possible to obtain a constant form a java properties file? I am trying to develop my application so that I can set a flag in a master properties file that dictates whether the application uses the development config file or the production one.
Most of application works fine but Ive hit a bit of a brick wall with the database table mapping in the entity classes. I am using Dynamo DB so the actual class itself requires an annotation as follows:
#DynamoDBTable(tableName = "table_name")
public class EmailTemplates {
...
The tableName value must be a constant and I'm trying to use the following to retrieve the value from the properties file and pass it to the tableName;
#DynamoDBTable(tableName = DynamoTable.TABLE_NAME)
public class EmailTemplates {
...
The DynamoTable class:
public final class DynamoTable {
public static final String TABLE_NAME = ResourceBundle.getBundle(ResourceBundle.getBundle("ProjectStage").getString("ProjectStage")).getString("EmailTemplates");
}
Unfortunately its not working as its saying the value is not a constant. If I simply put a literal string (ie. "aStringValue") then its fine, but not from the properties file.
NB. Just to be clear there isn't a problem with the above code retrieving the values from the properties file. The problem is that its not being treated as a constant.
You can't do what you want to do.
You're asking the javac compiler to execute arbitrary code to read a properties file from disk, extract a value, and insert that as a constant into your code (at compile time).
As you can see, that's a bit much for the compiler to do.
You can only execute that code at runtime, which doesn't suite your situation because you're trying to assign a value to an annotation (and thus the value for the annotation must be available at compile time).
If you are using the DynamoDBMapper class for your database interaction, there is the option to provide an extra DynamoDBMapperConfig argument for loads, saves, deletes, queries and scans.
You can build this config at runtime and then pass it into the dynamoDB operations.
private DynamoDBMapperConfig getEnvironmentConfig(DymanoTable tableEntity, String environment)
{
DynamoDBTable annotation = (DynamoDBTable) tableEntity.getClass().getAnnotation(DynamoDBTable.class);
DynamoDBMapperConfig.TableNameOverride tableNameOverride = new DynamoDBMapperConfig.TableNameOverride(environment + annotation.tableName());
return new DynamoDBMapperConfig(tableNameOverride);
}
You will need to create a DymnamoDBMapper...
AWSCredentials credentials = new PropertiesCredentials(
ObjectPersistenceQueryScanExample.class.getResourceAsStream("AwsCredentials.properties"));
client = new AmazonDynamoDBClient(credentials);
DynamoDBMapper mapper = new DynamoDBMapper(client);
And the use this for your dynamoDB interaction
public void save(DynamoTable entity)
{
mapper.save(entity, getEnvironmentConfig(entity,"dev"));
}
i was wondering if it's possible to initialize a constant in an interface from a property file using java or using spring messageSource, or such thing is not possible
please advise, thanks.
You can:
public interface Foo {
String a = Properties.getProperty("foo"); // public static final by default
}
However, that means that Properties.getProperty(..) has to be a static method which relies on an already initialized message source (statically again). Depending on the project and the frameworks you use this might not be the best option.
You could initialise a bean via a configuration which includes a final member. Since it's final you can assign to it during construction/initialisation and it then is immutable.
To configure from a property file using Spring, check out the PropertyPlaceholderConfigurer. That will allow you to initialise Spring beans using one or more property files from your classpath, filesystem, remote services etc.
Yes, that's possible:
public static final CONSTANT = System.getProperty("myProperty");
Although it's possible using some static helper method (as was already suggested), I would strongly recommend you not to do so for 2 reasons:
That looks like a pretty bad design. If you need a dynamic value - make it a method in the interface. Or use a static helper directly - you will need one anyway to make it work.
Constants might be inlined at compile time. That shouldn't happen in this particular case - compiler should go with inlining only if it can prove that value won't change between executions, basically if you initialize it with a literal, But there is a tiny chance that it would. Just think how bad will it be - no matter in which environment the progran is running, it picks up some useless value set during compilation, instead of what is configured. (This is rather a theoretical problem, need to say).
by reading a property file like in the example below.
int property1;
String otherProperty;
public void loadProperties(File propFile) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(propFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Property1=")) {
property1 = Integer.parseInt(line.substring(10));
}
if (line.startsWith("OtherProperty=")) {
otherProperty = line.substring(14);
}
}
}
This might be an age old problem and I am sure everyone has their own ways.
Suppose I have some properties defined such as
secret.user.id=user
secret.password=password
website.url=http://stackoverflow.com
Suppose I have 100 different classes and places where I need to use these properties.
Which one is good
(1) I create a Util class that will load all properties and serve them using a key constant
Such as :
Util is a singleton that loads all properties and keeps up on getInstance() call.
Util myUtil = Util.getInstance();
String user = myUtil.getConfigByKey(Constants.SECRET_USER_ID);
String password = myUtil.getConfigByKey(Constants.SECRET_PASSWORD);
..
//getConfigByKey() - inturns invokes properties.get(..)
doSomething(user, password)
So wherever I need these properties, I can do steps above.
(2) I create a meaningful Class to represent these properties; say,
ApplicationConfig and provide getters to get specific properties.
So above code may look like:
ApplicationConfig config = ApplicationConfig.getInstance();
doSomething(config.getSecretUserId(), config.getPassword());
//ApplicationConfig would have instance variables that are initialized during
// getInstance() after loading from properties file.
Note: The properties file as such will have only minor changes in the future.
My personal choice is (2) - let me hear some comments?
Do it the most straightforward way (a class with static values):
package com.domain.packagename
public class Properties {
private static String hostName;
public static getHostName() { return hostName; }
private static int port;
public static int getPort() { return port; }
public static void load() {
//do IO stuff, probably
hostName = ??;
port = ??;
//etc
}
}
I find the first approach to be more verbose than necessary. (Especially if the properties are not expected to change very much.) Also, by using the second approach you can handle casting/type issues when the properties are loaded instead of when they are used.
Your option (2) to keep application specific getters sounds better and clean.
public static final keys from an interface had been a bad design in Java for ages.
I guess my first question is why you want to create an instance of something you're saying is a singleton (you mentioned using code like Util.getInstance()). A singleton only has 1 instance so you shouldn't try to instantiate multiple copies in your code.
If the data is static (like this appears to be) I'd create a singleton and retrieve the values from it.
I don't think there is any significant advantage of one method over the other and I don't think the solution (1) is more secure, just because it provides a property key instead of a java getter for getting passwords.
If I had to chose one though I would take option (2).