Java concatenation in properties file - java

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

Related

Text not found in .txt , but it's already there

I am going through Mooc.fi Java course and I can't figure how not to write String into file if the file already contains it. I tried only with one String and tried without " " (empty space), and without another string, but still it adds the string even when the file already contains it.
And translate() method doesn't find/return whole line in which it found the given word.
public class main {
public static void main(String[] args) throws Exception {
MindfulDictionary dict = new MindfulDictionary();
dict.add("apina", "monkey");
dict.add("banaani", "banana");
dict.add("apina", "apfe");
System.out.println( dict.translate("apina") );
System.out.println( dict.translate("monkey") );
System.out.println( dict.translate("programming") );
System.out.println( dict.translate("banana") );
}
}
public class MindfulDictionary {
File file;
FileWriter writer;
Scanner imeskanera;
public MindfulDictionary() throws Exception {
this.file = new File("C:\\Users\\USER\\Desktop\\test.txt");
this.imeskanera = new Scanner(this.file, "UTF-8");
}
public void add(String word, String translation) throws Exception {
boolean found = false;
while(this.imeskanera.hasNextLine()) {
String lineFromFile = this.imeskanera.nextLine();
if(word.contains(lineFromFile)) {
found = true;
break;
}
}
if(!found) {
this.writer = new FileWriter(this.file,true);
this.writer.write(word +" " + translation +"\n");
this.writer.close();
}
}
public String translate(String word) throws Exception {
String line = null;
while(this.imeskanera.hasNextLine()) {
String data = this.imeskanera.nextLine();
if(data.contains(word)) {
line = data;
break;
}
}
return line;
}
}
The problem is that your Scanner object has already been consumed by the add() method. You need to reopen the input stream in order to read the contents of the file. If you add
this.imeskanera = new Scanner(this.file, "UTF-8");
At the beginning of the translate() method, it should word. Which basically tell you that there is no need for Scanner to be a global field. Use it locally in each method. This is how I have explain the concept of file streams in the past:
Think about file streams (for reading and writing) logically. You
cannot allow for such a stream to be "circular". Otherwise, when you
try to get the "next line", there will always be a next line and you
will never be able to stop reading (or writing). The stream is
consumed when it reach the end, and once that is done, to go back to
the beginning of the stream, you will need to open a new one; not
reuse the old one.
I thought I needed to add this explanation even after the answer was accepted because I know new developer struggle with this concept and it because of that, it is necessary to explain it in detail.
With that said, your MindfulDictionary class should look like this:
public class MindfulDictionary {
File file;
FileWriter writer;
// Scanner imeskanera;
public MindfulDictionary() throws Exception {
this.file = new File("test.txt"); // I changed the path to the file to make it work for me. You can change it back if you want to.
file.createNewFile();
}
public void add(String word, String translation) throws Exception {
Scanner imeskanera = new Scanner(this.file, "UTF-8");
boolean found = false;
while (imeskanera.hasNextLine()) {
String lineFromFile = imeskanera.nextLine();
if (word.contains(lineFromFile)) {
found = true;
break;
}
}
if (!found) {
this.writer = new FileWriter(this.file, true);
this.writer.write(word + " " + translation + "\n");
this.writer.close();
}
imeskanera.close();
}
public String translate(String word) throws Exception {
Scanner imeskanera = new Scanner(this.file, "UTF-8");
String line = null;
while (imeskanera.hasNextLine()) {
String data = imeskanera.nextLine();
if (data.contains(word)) {
line = data;
break;
}
}
imeskanera.close();
return line;
}
}
I ran your code with my modifications and now the output is
apina monkey
apina monkey
null
banaani banana
In addition to the Scanner issue mentioned by the answer of #hfontanez, following changes.
if (word.contains(lineFromFile))
This checks if the first word contains the line, this is not true. The file contains the first word and translation. so this can be changed to
if (lineFromFile.contains(word))
as #ghostCat mentioned searching the key(word) can be refactored. Code with these changes.
public class MindfulDictionary {
File file;
FileWriter writer;
// Scanner imeskanera;
public MindfulDictionary() throws Exception {
this.file = new File("test.txt");
file.createNewFile();
}
public void add(String word, String translation) throws Exception {
if (get(word) == null) {
this.writer = new FileWriter(this.file, true);
this.writer.write(word + " " + translation + "\n");
System.out.println("Out>>:"+word + " " + translation + "\n");
this.writer.close();
}
}
private String get(String word) throws Exception {
Scanner imeskanera = new Scanner(this.file, "UTF-8");
boolean found = false;
String retStr= null;
while (imeskanera.hasNextLine()) {
String lineFromFile = imeskanera.nextLine();
if (lineFromFile.contains(word)) {
found = true;
retStr=lineFromFile;
break;
}
}
imeskanera.close();
return(retStr);
}
public String translate(String word) throws Exception {
return get(word);
}
public static void main(String[] args) throws Exception {
MindfulDictionary dict = new MindfulDictionary();
dict.add("apina", "monkey");
dict.add("apina", "monkey");
dict.add("banaani", "banana");
dict.add("apina", "apfe");
System.out.println( dict.translate("apina") );
System.out.println( dict.translate("monkey") );
System.out.println( dict.translate("programming") );
System.out.println( dict.translate("banana") );
}
}

Adding a String to a file name and still be able to use it

I have a xml file that I'm getting its full path, and pass it to a function where I add a String to its name. However I'm not being able to use it (the initial fullpath) after adding the string. How can it be done, that after getting the fullpath in search(String dirName), and adding the string in lk(String fullpath), I can still use the path which is returned by search(String dirName).
public String search( String dirName)throws Exception{
String fullPath = null;
File dir = new File(dirName);
if ( dir.isDirectory() )
{
String[] list = dir.list(new FilenameFilter()
{
#Override
public boolean accept(File f, String s )
{
return s.endsWith(".xml");
}
});
if ( list.length > 0 )
{
fullPath = dirName+list[0];
lockFile(fullPath);
return fullPath;
}
}
return "";
}
public void lk( String fullPath) throws Exception {
File f = new File(fullPath);
String fileNameWithExt = f.getName();
try {
File newfile =new File(fileNameWithExt+".lock");
if(f.renameTo(newfile)){
System.out.println("Rename succesful");
}else{
System.out.println("Rename failed");
}
} catch (Exception e) {
e.printStackTrace();
}
}
try this
File originalFile = new File(<file parent path>, "myxmlfile");
File cloneFile = new File(originalFile.getParent(),
originalFile.getName()+"<anything_i_want_to_add>");
Files.copy(originalFile.toPath(),cloneFile.toPath());
//now your new file exist and you can use it
originalFile.delete();//you delete the original file
...
//after you are done with everything and you want the path back
Files.copy(cloneFile.toPath(),originalFile.toPath());
cloneFile.delete();
In your lock method, you are calling renameTo method. Because of that, the original filename is now gone, and is replaced by the new filename that ends with .lock.
The java.io.File class is not a file pointer but an object to hold a filename. Using a file object that still refers to an old filename will cause an error.
To answer your question: If you want the old filename after locking, you must use a different approach in locking your file. For example, MS Access locks their .accdb files by creating a lockfile with the same filename as the opened .accdb file.
You may use this code as a reference:
public boolean fileIsLocked(File file) {
File lock = new File(file.getAbsolutePath() + ".lock");
return lock.exists();
}
public void lockFile(File file) {
if (!fileIsLocked(file)) {
File lock = new File(file.getAbsolutePath() + ".lock");
lock.createNewFile();
lock.deleteOnExit(); // unlocks file on JVM exit
}
}
public void unlockFile(File file) {
if (fileIsLocked(file)) {
File lock = new File(file.getAbsolutePath() + ".lock");
lock.delete();
}
}

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.

How to load Properties only once in 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.

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;
}

Categories