I have an XPages application for Swedish users.
When I am sending a message to the facescontext via
msg = propStrings.getProperty("gen_CustDateDecided") ;
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage("msgBox", new javax.faces.application.FacesMessage(msg));
The text for the that is broadcasted resides on a properties file, with UTF-8 encoding.
When loading the properties file I make sure it is read in UTF-format:
private Properties getPropertiesFromFile(String fileName) {
Properties prop = new Properties();
try {
InputStream is = FacesContextEx.getCurrentInstance().getExternalContext().getResourceAsStream(fileName);
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
prop.load(r);
} catch (Exception e) {
XspOpenLogUtil.logEvent(null, null, fileName, Level.WARNING, null);
}
return prop;
}
The text that appears on the messages control on the Xpage:
Senaste beslutsdatum i kundkommittén
The text in the properties file:
gen_CustDateDecided=Senaste beslutsdatum i kundkommittén
What have I done wrong?
Property files are not encoded as UTF-8. They are ISO 8859-1. You need to encode them accordingly. Easiest is to just use a few lines in a standalone Java class to save properties. Takes care of encoding.
More details here:
How to use UTF-8 in resource properties with ResourceBundle
Related
I am making a program that works with MySQL database,for now i store URL, login, password e.t.c as public static String. Now i need to make it possible to work on another computer, so database adress will vary, so i need a way to edit it inside programm and save. I would like to use just external txt file, but i don't know how to point it's location.
I decided to make it using Property file, i put it in src/res folder. It work correct while i'm trying it inside Intellij Idea, but when i build jar (artifact) i get java.io.FileNotFoundException
I tried two ways:
This one was just copied
private String getFile(String fileName) {
StringBuilder result = new StringBuilder("");
//Get file from resources folder
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
System.out.println(file.length());
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
result.append(line).append("\n");
}
scanner.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
System.out.println(obj.getFile("res/cfg.txt"));</code>
And second one using Properties class:
try(FileReader reader = new FileReader("src/res/cfg.txt")) {
Properties properties = new Properties();
properties.load(reader);
System.out.println(properties.get("password"));
}catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
In both ways i get java.io.FileNotFoundException. What is right way to attach config file like that?
Since the file is inside a .JAR, it can't be accessed via new File(), but you can still read it via the ClassLoader:
Properties properties = new Properties();
try (InputStream stream = getClass().getResourceAsStream("/res/cfg.txt")) {
properties.load(stream);
}
Note that a JAR is read-only. So this approach won't work.
If you want to have editable configuration, you should place your cfg.txt outside the JAR and read it from the filesystem. For example like this:
Properties properties = new Properties();
File appPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile();
try (InputStream stream = new FileInputStream(new File(appPath, "cfg.txt"))) {
properties.load(stream);
}
There are multiple places your can place your configuration options, and a robust deployment strategy will utilize some (or all) of the following techniques:
Storing configuration files in a well known location relative to the user's home folder as I mentioned in the comments. This works on Windows (C:\Users\efrisch), Linux (/home/efrisch) and Mac (/Users/efrisch)
File f = new File(System.getProperty("user.home"), "my-settings.txt");
Reading environment variables to control it
File f = new File(System.getenv("DEPLOY_DIR"), "my-settings.txt");
Using a decentralized service such as Apache ZooKeeper to store your database settings
Use Standalone JNDI
(or the JNDI built-in to your deployment target)
Use a Connection Pool
I have a simple method that reloads config after file has been modified.
private Properties loadCustomProperties(File config) throws IOException {
Properties properties = new Properties();
try (FileInputStream inStream = new FileInputStream(config)) {
properties.load(inStream);
}
return properties;
}
Now if I run this code from IDE (Intellij) everything works fine, but when run using Spring bootstrap jar it loads 2nd last version of the file. So basicaly if I have inital value prop=1, then change it to prop=2, I still have prop=1 loaded. If I change it to prop=3, I end up with loaded prop=2 and so on.
System is Ubuntu 18.04.
Properties look like this:
cache.size=1000
And the expected output is to get latest version of the file.
I suggest you building an utility method for reading the single property, so you can easly load all properties that you need 1 by 1, something like (in my example the config file is named config.properties):
public static String getPropertyValue(String property) throws IOException {
Properties prop = new Properties();
String propFileName = "config.properties";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(propFileName);
if (inputStream != null) {
prop.load(inputStream);
} else {
throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath");
}
return prop.getProperty(property);
}
So if in your config.properties file you put something like
cache.size=1000
when you call getPropertyValue("cache.size") you will get 1000
I am using Selenium to test an e-commerce application. I need to check the items listed on selecting a category on the listing page match with items in the Database. So I am accessing pages using selenium and storing the page source in a text file. I later parse this text file using HTMLCleaner and JSoup to get the field I wish to validate with the DB.
However, I noticed that some products listed on the page use special characters like ™ , ® and so on which are not stored/retrieved correctly and displayed as question marks.
Code I am using to store the page source:
BufferedWriter writer = null;
try
{
writer = new BufferedWriter(new FileWriter(filepath+"/"+filename+".txt"));
writer.write(driver.getPageSource());
}
catch ( IOException e)
{
e.printStackTrace();
}
finally
{
try
{
writer.close( );
}
catch (IOException e)
{
}
}
Retrieving and parsing file
Document htmlFile = Jsoup.parse(fileSavedPreviously,"ISO-8859-1");
TagNode tagNode = new HtmlCleaner().clean(fileSavedPreviously);
try {
org.w3c.dom.Document doc = new DomSerializer(new CleanerProperties())
.createDOM(tagNode);
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
//rest of the parsing....
Define the encoding for the stream writer :
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fullpath), "UTF-8"));
And provide the same one to the parser :
Document htmlFile = Jsoup.parse(fileSavedPreviously, "UTF-8");
To get the encoding of the page, execute document.inputEncoding in the browser console.
If you use the constructors of FileWriter it will use the default charset which doesn't cover those special characters obviously if you face such issue so you should instead use the constructors of OutputStreamWriter to define explicitly the character encoding as next:
writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(String.format("%s/%s.txt", filepath, filename)), charsetName
)
);
Since ISO-8859-1 covers ® but not ™, you should use a unicode charset such as UTF-8 and set it in both places where you write your content and where you read it.
I am trying to set up a java .properties file outside of the packaged jar. This is my code to load it:
public static final String FILENAME = "test.properties";
public static void load() throws IOException {
FileInputStream fis = null;
try {
props = new Properties();
fis = new FileInputStream(FILENAME);
props.load(fis);
System.out.println("Properties successfully loaded: "+props);
validateProperties();
} catch (FileNotFoundException e) {
System.err.println("Properties file not found. Creating...");
new File(FILENAME).createNewFile();
//fill with default properties
System.out.println("Properties file successfully created");
} finally {
if (fis != null) try {fis.close();} catch(Exception e) {}
}
}
Unfortunately, when I run this, I get the following output:
Properties successfully loaded: {}
Here is test.properties:
#no comment
#Sun Jun 23 19:21:45 CDT 2013
port=55142
handSize=10
maxPlayers=8
timeout=1500
I have confirmed, by manually reading and printing, that the FileInputStream is reading from the correct file. So why aren't my properties loading?
EDIT: Here is some code which loads the contents of the properties file directly:
public static void test() throws IOException {
FileInputStream fis = new FileInputStream(FILENAME);
byte[] b = new byte[fis.available()];
fis.read(b);
String text = new String(b);
System.out.println(text);
}
and it outputs:
#no comment
#Sun Jun 23 19:21:45 CDT 2013
port=55142
handSize=10
maxPlayers=8
timeout=500
so the FIS must be reading from the correct file.
EDIT 2: Ok, so I don't know what the problem was, but I restarted eclipse and now it's working. Very sorry to have wasted your time.
Check what line separator your java system uses. Eg:
System.out.println((int)System.getProperty("line.separator").charAt(0));
On UNIX that will give 10, which is newline \n, on Windows that will be 13 (eg: the first char of \r\n).
I think your java code is reading the file using Windows encoding, yet the property file is edited in UNIX, hence everyting appears to be in "one single line" -- which will result in empty properties because your first line is commented
As your properties file is not present in the classpath so you cannot read it without giving the proper path. There are multiple approaches to read an external properties file from a jar. One of the simplest way is to use the -D switch to define a system property on a java command line. That system property may contain a path to your properties file.
E.g
java -cp ... -Dmy.app.properties=/path/to/test.properties my.package.App
Then, in your code you can do :
public static final String FILENAME = "test.properties";
public static void load() throws IOException {
FileInputStream fis = null;
String propPath = System.getProperty(FILENAME);
try {
props = new Properties();
fis = new FileInputStream(propPath);
props.load(fis);
System.out.println("Properties successfully loaded: "+props);
validateProperties();
} catch (FileNotFoundException e) {
System.err.println("Properties file not found. Creating...");
new File(propPath ).createNewFile();
//fill with default properties
System.out.println("Properties file successfully created");
} finally {
if (fis != null) try {fis.close();} catch(Exception e) {}
}
}
When there is no absolute path mentioned, JVM tries to load resources from the JVM & project classpath. In your case, empty output signifies that JVM is trying to load property file from classpath but the file is not there.
Solutions:
1) Either place your property file in your classpath
2) Or mention absolute path to property file.
A ResourceBundle offers a very easy way to access key/value pairs in a properties file in a Java...
You can refer following.
http://www.avajava.com/tutorials/lessons/how-do-i-read-a-properties-file-with-a-resource-bundle.html
You can directly specify your properties file name while loading the bundle when it is present in the same folder as your jar/classes.
I have a single UTF-8 encoded String that is a chain of key + value pairs that is required to be loaded into a Properties object. I noticed I was getting garbled characters with my intial implementation and after a bit of googling I found this Question which indicated what my problem was - basically that Properties is by default using ISO-8859-1. This implementation looked like
public Properties load(String propertiesString) {
Properties properties = new Properties();
try {
properties.load(new ByteArrayInputStream(propertiesString.getBytes()));
} catch (IOException e) {
logger.error(ExceptionUtils.getFullStackTrace(e));
}
return properties;
}
No encoding specified, hence my problem. To my question, I can't figure out how to chain / create a Reader / InputStream combination to pass to Properties.load() that uses the provided propertiesString and specifies the encoding. I think this is mostly due to my inexperience in I/O streams and the seemingly vast library of IO utilities in the java.io package.
Any advice appreciated.
Use a Reader when working with strings. InputStreams are really meant for binary data.
public Properties load(String propertiesString) {
Properties properties = new Properties();
properties.load(new StringReader(propertiesString));
return properties;
}
private Properties getProperties() throws IOException {
ClassLoader classLoader = getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("your file");
InputStreamReader inputStreamReader = new InputStreamReader(input, "UTF-8");
Properties properties = new Properties();
properties.load(inputStreamReader);
return properties;
}
then usage
System.out.println(getProperties().getProperty("key"))
Try this:
ByteArrayInputStream bais = new ByteArrayInputStream(propertiesString.getBytes("UTF-8"));
properties.load(bais);