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;
}
Related
I have ConfigProperties.class
public class ConfigProperties {
#BeforeTest
public void TestDataSetup() throws FileNotFoundException {
File src = new File("src\\main\\resources\\config.properties");
FileInputStream fis = new FileInputStream(src);
ConfigProperties properties = new ConfigProperties();
properties.load(fis);
}
public void load(FileInputStream fis) {
}
}
below test method
public class Paragraphs extends ConfigProperties {
Properties prop = new Properties();
public void createParagraph() {
RestAssured.baseURI = prop.getProperty("paragraphsURL");
here is config.properties
paragraphsURL=http://192.168.0.139:8880/paragraphs
After running my test I received error
java.lang.IllegalArgumentException: baseURI cannot be null
After debugging I have
RestAssured.baseURI = Class not loaded : io.restassured.RestAssured
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
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.
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.
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;
}