How to load Properties only once in java? - java

I have loaded property file in java.
public String getproperties(String property)
InputStream inputStream = new ClassPathResource("test.properties").getInputStream();
Properties testProperties = new Properties();
testProperties.load(inputStream);
inputStream.close();
return testProperties.getProperty(propertyType);
}
Its loaded successfully.The problem is every time property file loaded instead of loading only once.
How to achieve this?

Store the Properties object as a field outside the method, initially null, and only create it on first call:
private Properties testProperties = null;
public String getproperties(String property)
if (testProperties == null) {
InputStream inputStream = new ClassPathResource("test.properties").getInputStream();
testProperties = new Properties();
testProperties.load(inputStream);
inputStream.close();
}
return testProperties.getProperty(propertyType);
}

You can easily cache the properties by doing something like this:
class PropertyContainer {
private static Properties properties;
public static synchronized Properties getProperties() {
if (properties != null) { return properties; }
InputStream inputStream = new ClassPathResource("test.properties").getInputStream();
properties = new Properties();
properties.load(inputStream);
inputStream.close();
}
}
Your old getproperties method would then be something like this:
return PropertyContainer.getProperties().getProperty(propertyType);
This of course assumes that you only need one property file.

I usually wrap this into a private method, storing the object into a private field:
private Properties _testProperties;
private Properties properties() {
if (_testProperties == null) {
InputStream inputStream = new ClassPathResource("test.properties").getInputStream();
_testProperties = new Properties();
inputStream.close();
_testProperties.load(inputStream);
}
return _testProperties ;
}
public String getproperties(String property) {
return properties().getProperty(property);
}

Just create class field Properties properties:)
And save once loaded values there.

Related

Java concatenation in properties file

I have created a properties file called myproperties.properties as:
test.value1=one
test.value2=two
My java code to read this file is the following:
String test = Utility.getInstance().getProperty("test.value1");
where class Utility is so defined:
public class Utility {
private static Utility _instance = null;
private static Properties properties = new Properties();
static public Utility getInstance(){
if (_instance == null) {
_instance = new Utility();
}
return _instance;
}
private Utility(){
loadUtility();
}
public String getProperty(String tgtPropertyName) {
Object prop = properties.get(tgtPropertyName);
if (prop != null) {
return prop.toString();
} else {
return null;
}
}
private void loadUtility(){
String filename = null;
try{
filename = getClass().getClassLoader().getResource("myproperties").getFile();
InputStream file = new FileInputStream(new File(filename));
properties.load(file);
Iterator iter = properties.keySet().iterator();
while (iter.hasNext()){
System.out.println("FILE LOADED");
}
}catch(Exception e){
}
}
}
This code works correctly. Now I must add a concatenation in my properties file:
test.value3=${test.value1}${test.value2}
and this not worked because my Java code cannot interpret ${}.
The exception is:
Caused by: java.lang.IllegalStateException: Stream handler unavailable due to: For input string: "${test.value1}"
Why?
Use below code to concatenate in type.value3 in properties file
Properties prop=null;
public FileReader FileLoader() throws FileNotFoundException
{
File file=new File("myproperties.properties");
FileReader fileReader=new FileReader(file);
return fileReader;
}
public String propertyLoader(String key) throws IOException
{
FileReader fileReader=FileLoader();
prop=new Properties();
prop.load(fileReader);
String value=prop.getProperty(key);
return value;
}
public void resultWriter() throws IOException
{
String value1=propertyLoader("test.value1");
String value2=propertyLoader("test.value2");
String res=value1+value2;
System.out.println(res);
FileWriter fw=new FileWriter("myproperties.properties");
prop=new Properties();
prop.setProperty("test.value3", res);
prop.store(fw, null);
}
public static void main(String[] args) throws IOException
{
UtilityNew util=new UtilityNew();
util.resultWriter();
System.out.println("Success");
}
Nested properties are not supported in core Java. The only thing you can do is create a class that is going to resolve the ${XXX} values once you have loaded the file.properties into a Properties object.
Or maybe the typesafe library can be usefull to you. https://github.com/lightbend/config. It has a lot of functionalities and one of them is substitutions:
substitutions ("foo" : ${bar}, "foo" : Hello ${who})
But you won't have a key-value properties file anymore, it will look more like a json file.
This might be a late answer but someone might find this useful.
You can write a small utility function which reads the property values and then iteratively replaces any nested values that are present
First search for your pattern. Replace it with the actual value by looking-up at the properties. Repeat this until you get the final string.
Properties properties = new Properties();
properties.setProperty("base_url", "http://base");
properties.setProperty("subs_url", "${base_url}/subs");
properties.setProperty("app_download", "apps/download");
properties.setProperty("subs_detail", "${subs_url}/detail/${app_download}");
String input = properties.getProperty("subs_detail");
Pattern pattern = Pattern.compile("\\$\\{.*?\\}"); //change the pattern here to find nested values
while (pattern.matcher(input).find())
{
Matcher match = pattern.matcher(input);
while (match.find())
{
input = input.replace(match.group(), properties.getProperty(match.group().substring(2, match.group().length()-1)));
}
}
System.out.println("final String : " + input); // this prints http://base/subs/detail/apps/download

differentiate between multiple properties files

My application has different customers (around 20) , every customer has their own *.properties file with the connection settings, property parameters are the same.
Currently I have for every customer an own method to read the properties and store it in Customer. With 20 Customers, its inflated. I'm searching now for a better solution.
private final static Customer get_CustomerXXXX() {
final Properties p = new Properties();
p.load(S.class.getResourceAsStream("customerXXX.properties"));
return new Customer (p.getProperty("PARAM1", p.getProperty("PARAM2", p.getProperty("PARAM3")
}
if(SPECIFIC_CUSTOMER.XXXX) {
customerSettings = get_CustomerXXXX();
} else if(SPECIFIC_CUSTOMER.BBBB) {
customerSettings = get_CustomerBBBB();
}
property parameters are the same
if you are sure that in future also i'll be same. then you can read the property file first time only. From next time on wards, use values loaded from previous property file.
You can combine Singleton and Factory Method design patterns here.
You should have a method such as following:
private final static Properties getProperties(String idetifier)
{
Properties p = new Properties();
p.load(S.class.getResourceAsStream("customer"+idetifier+".properties"));
return p;
}
public class CustomerTest {
private String identifier;
public CustomerTest(String identifier) {
this.identifier = identifier;
}
public Properties getProerties() {
Properties p = null;
try {
p = new Properties();
p.load(CustomerTest.class.getResourceAsStream("customer" + identifier + ".properties"));
} catch (IOException e) {
e.printStackTrace();
}
return p;
}
}
this would be the way you suggested in the comments #OP.

RestFul web service which reads properties file

I have got couple of Jersey REST Web services say SendPassword and ResetPassword whose purpose is to send email .
For sending email , i have configured a properties file under tomcat and all this works fine
The code of the SendPassword.java is somewhat this way
#Path("/sendpassword")
public class SendPassword {
#GET
#Produces("application/json")
public String sendPasswordToEmail(#QueryParam("empid") String empid)
throws JSONException
{
try {
SendEmailUtility.sendmail("weqw","2312");
}
catch(Exception e)
{
}
}
SendEmailUtility.java
public class SendEmailUtility
{
public static String sendmail(String sendemalto,String generatedpwd) throws IOException {
String result = "fail";
File configDir = new File(System.getProperty("catalina.base"), "conf");
File configFile = new File(configDir, "email.properties");
InputStream stream = new FileInputStream(configFile);
Properties props_load = new Properties();
props_load.load(stream);
final String username = props_load.getProperty("username");
final String password = props_load.getProperty("password");
Properties props_send = new Properties();
props_send.put("mail.smtp.auth","true");
props_send.put("mail.smtp.starttls.enable","true");
Transport.send(message);
// Some code to send email
result = "success";
} catch (MessagingException e) {
result = "fail";
e.printStackTrace();
}
return result;
}
}
As you can see i am reading the properties file for every call of the websercice
(As reading operation is somewhat costly) , Is there any way to resolve this ??
Could you please let me know whats the best approach to handle this.
Thanks in advance .
There are few ways to do this the one way of doing it is to make the props_load a private static member of the class and call it like this
public class SendEmailUtility
{
private static Properties props;
private static Properties getProperties() {
if (props == null) {
File configDir = new File(System.getProperty("catalina.base"), "conf");
File configFile = new File(configDir, "email.properties");
InputStream stream = new FileInputStream(configFile);
props = new Properties();
props.load(stream);
}
return props;
}
public static String sendmail(String sendemalto,String generatedpwd) throws IOException {
String result = "fail";
Properties props_load = getProperties();
final String username = props_load.getProperty("username");
final String password = props_load.getProperty("password");
Properties props_send = new Properties();
props_send.put("mail.smtp.auth","true");
props_send.put("mail.smtp.starttls.enable","true");
Transport.send(message);
// Some code to send email
result = "success";
} catch (MessagingException e) {
result = "fail";
e.printStackTrace();
}
return result;
}
}
The other design I would suggest is to make an email service class like EmailSender or EmailService and then inject it into SendPassword class
#Path("/sendpassword")
public class SendPassword {
#Autowired
EmailService emailService;
#GET
#Produces("application/json")
public String sendPasswordToEmail(#QueryParam("empid") String empid)
throws JSONException
{
I would recommend using resource bundle, which does not need InputStream
create a properties file and put directly inside your packages along with your java code
example folder structure
com
- preethi
-SendPassword.java
-email.properties
Then you can code like
ResourceBundle props_load = ResourceBundle.getBundle("com.preethi.email");
final String username = props_load.getString("username");
This way you don't have to worry about opening and closing the stream or file path
You could use a lazy-getter to fetch and cache the Properties object.
private static Properties props;
private static Properties getProperties() {
if (props == null) {
File configDir = new File(System.getProperty("catalina.base"), "conf");
File configFile = new File(configDir, "email.properties");
InputStream stream = new FileInputStream(configFile);
props = new Properties();
props.load(stream);
}
return props;
}
Each time you want to use the Properties, call getProperties(). It will cache it the first time it's called. Each subsequent call will just return the cached object.
Note: This example does not catch any exceptions.

loading the properties file

I wanted to read some properties file.
For that I created a small program which reads, writes and also updates this properties file.
Now some people are saying the properties file should be read only once, that means when the class is loaded it should read once, not multiple times for each key.
So I have to read the properties file inside a static block.
Now my doubt if I make any new entry to the properties file, will it be loaded the new entry ?
Please suggest me which is the correct way to design the loading of properties file.
public class Parser {
private String path;
private static Properties prop = new Properties();
public Parser(String path) throws IOException{
this.path = path;
load();
}
public Model readPropertiesFile(){
Model model = new Model();
model.setName(prop.getProperty("name"));
return model ;
}
public void createOrUpdatePropertiesFile(Model model){
prop.setProperty("name", model.getName());
}
public void setPath(String path){
this.path = path;
}
public String getPath(){
return path ;
}
public void load() throws IOException{
File file = new File(path);
if(!file.exists()){
file.createNewFile();
System.out.println("File created..");
}
prop.load(new FileInputStream(file));
}
You can try this ways;
Load properties file from classpath
public static Properties load(String propsName) throws Exception {
Properties props = new Properties();
URL url = ClassLoader.getSystemResource(propsName);
props.load(url.openStream());
return props;
}
Load a properties file
public static Properties load(File propsFile) throws IOException {
Properties props = new Properties();
FileInputStream fis = new FileInputStream(propsFile);
props.load(fis);
fis.close();
return props;
}

How to get back Map from .txt file use Properties?

This is code to write hashtable to .txt file !
public static void save(String filename, Map<String, String> hashtable) throws IOException {
Properties prop = new Properties();
prop.putAll(hashtable);
FileOutputStream fos = new FileOutputStream(filename);
try {
prop.store(fos, prop);
} finally {
fos.close();
}
}
How we getback the hashtable from that file ?
Thanks
In the very same ugly manner:
#SuppressWarnings("unchecked")
public static Map<String, String> load(String filename) throws IOException {
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(filename);
try {
prop.load(fis);
} finally {
fis.close();
}
return (Map) prop;
}
Use Properties.load()
code example:
public static Properties load(String filename) {
FileReader reader = new FileReader(filename);
Properties props = new Properties(); // The variable name must be used as props all along or must be properties
try{
props.load(reader);
} finally {
reader.close();
}
return props;
}
Edit:
If you want a map back, use something like this. (The toString is to avoid a cast - you can cast to String if you would prefer)
public static Map<String, String> load(String filename) {
FileReader reader = new FileReader(filename);
Properties props = new Properties();
try {
props.load(reader);
} finally {
reader.close();
}
Map<String, String> myMap = new HashMap<String, String>();
for (Object key : props.keySet()) {
myMap.put(key.toString(), props.get(key).toString());
}
return myMap;
}

Categories