I have a class which reads a properties file. Please see below.
The method readProperties() is called many times when the application is running, does that mean there is a memory issue here?
public class PropertyReader {
private static Properties configKeyValuePairs = null;
private static String configPropertiesFileName = "Config.properties";
static void readProperties() throws FileNotFoundException, IOException {
configKeyValuePairs = new Properties();
InputStream input = ConfigReader.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
input.close();
}
static String getUserName(){
//return user name which is from the properties file.
}
}
Assuming your properties file never changes, you can do the following:
public class MyApplicationConfiguration {
private static Properties configKeyValuePairs = new Properties();
private static String configPropertiesFileName = "Config.properties";
static {
InputStream input = null;
try {
input = MyApplicationConfiguration.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
} catch (IOException e) {
// Deal with not being able to load config, could be a fatal error!
} finally {
if (input != null) {
input.close();
}
}
}
public static String getUsername() {
// ...
}
// Implement getters for other configuration key-value pairs
// DO NOT let configKeyValuePairs be returned to anyone
}
Load the properties object once, and store it a class member.
I find it hard to believe that you will have memory issues because of it.
If you find out that you do, then you can always comeback and rethink it, but don't prematurely optimize a problem that probably doesn't exist.
Yes, there could be a very big memory problem, depending on whether or not there are calling classes that hold a reference to the newly created properties object.
Try something like this:
public class PropertyReader {
private static Properties configKeyValuePairs = null;
private static final String configPropertiesFileName = "Config.properties";
public static void readProperties() throws FileNotFoundException, IOException {
if(null == configKeyValuePairs){
InputStream input;
synchronized(PropertyReader.class){
try{
configKeyValuePairs = new Properties();
input = PropertyReader.class
.getResourceAsStream(configPropertiesFileName);
configKeyValuePairs.load(input);
}finally{
//this can still throw ioexception!
if(null != input){
input.close();
}
}
}
}
}
Related
I have a jar file that I run from the console. In the program itself, I have to read data from the property file, which should be in the same folder as my jar file. How can i do this ?
my code which does not work correctly:
public class ReadProperties {
String propPath = System.getProperty("app.properties");
private String message;
private String userName;
ReadProperties() {
readProperties();
}
private void readProperties() {
final FileInputStream in;
try {
in = new FileInputStream(propPath);
Properties myProps = new Properties();
myProps.load(in);
message = myProps.getProperty(Constants.MESSAGE);
userName = myProps.getProperty(Constants.USERNAME);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getMessage() {
return message;
}
public String getUserName() {
return userName;
}
}
Note that the way you have coded above requires a system property to mark the file to load, passed as:
java -Dapp.properties=somefile.properties
If you intended a file called "app.properties" this requires a change to the declaration of propPath without System.getProperty
Your file handling should use try with resources to clean up afterwards with automatic close, and not hide any exception:
try (FileInputStream in = new FileInputStream(propPath)) {
// load here
}
You could provide default property values after exception, or handle by add throws IOException to the method, or append code to adapt as a runtime exception so that is is reported:
catch (Exception e) {
throw new UncheckedIOException(e);
}
I am using following code to redirect standard out and standard error out to Log file depending on the boolean value of a variable.
if (logToFile==true){
java.io.File outputFile = new java.io.File(logFilePath);
System.setOut(new java.io.PrintStream(new java.io.FileOutputStream(outputFile, true), true));
System.setErr(new java.io.PrintStream(new java.io.FileOutputStream(outputFile, true), true));
}
Moving further down my code, I want to find out whether my standard out and error out are associated with file - only then I would want to log few things. And over there, I don't have access to logToFile variable.
Is there any way to find out whether the standard out and error out are associated with file or the default console currently? And if they are associated to file then can we get the file path?
Moving further down my code, I want to find out whether my standard out and error out are associated with file - only then I would want to log few things. And over there, I don't have access to logToFile variable.
What about storing the value of logToFile in a static variable, like for example:
if (logToFile) {
StandardStreams.redirectToFile(new File(logFilePath));
}
public class StandardStreams {
private static boolean redirectedToFile;
public static void redirectToFile(File file) throws FileNotFoundException {
PrintStream stream = new PrintStream(new FileOutputStream(file, true), true);
System.setOut(stream);
System.setErr(stream);
redirectedToFile = true;
}
public static boolean areRedirectedToFile() {
return redirectedToFile;
}
}
And then:
if (StandardStreams.areRedirectedToFile()) {
// Log few things
}
Is there any way to find out whether the standard out and error out are associated with file or the default console currently? And if they are associated to file then can we get the file path?
Create your own PrintStream:
class ConsoleLinkedFile extends PrintStream {
private final File file;
ConsoleLinkedFile(File file) throws FileNotFoundException {
super(new FileOutputStream(file, true), true);
this.file = file;
}
File getFile() {
return file;
}
}
if (logToFile) {
PrintStream stream = new ConsoleLinkedFile(new File(logFilePath));
System.setOut(stream);
System.setErr(stream);
}
To find out and retrieve the file path:
public static Optional<File> getFileIfRedirected(PrintStream stream) {
if (stream instanceof ConsoleLinkedFile) {
ConsoleLinkedFile linkedFile = (ConsoleLinkedFile) stream;
return Optional.of(linkedFile.getFile());
}
return Optional.empty();
}
if (getFileIfRedirected(System.out).isPresent()) {
// Log few things
}
Note that the same PrintStream can be shared between standard input and standard error.
If you cannot create your own PrintStream, then you need to use reflection:
private static final VarHandle OUT, PATH;
static {
final Class<?> OUT_class = FilterOutputStream.class;
final Class<?> PATH_class = FileOutputStream.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
OUT = MethodHandles.privateLookupIn(OUT_class, lookup)
.findVarHandle(OUT_class, "out", OutputStream.class);
PATH = MethodHandles.privateLookupIn(PATH_class, lookup)
.findVarHandle(PATH_class, "path", String.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private static Optional<String> getFileIfRedirected(PrintStream stream) {
Object out = OUT.get(stream);
if (out instanceof BufferedOutputStream) {
out = OUT.get(out);
}
return Optional.ofNullable((String) PATH.get(out));
}
VarHandle is faster than java.lang.reflect. In Java 8, you can use the latter:
private static final Field OUT, PATH;
static {
try {
OUT = FilterOutputStream.class.getDeclaredField("out");
OUT.setAccessible(true);
PATH = FileOutputStream.class.getDeclaredField("path");
PATH.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}
I have written some code to generate passwords for users that were written to sql before. Then I wanted to write each user with username and password to xml. The code seems to work fine except at around 200th user it suddenly stops halfway through xml tag and ends, which is pretty weird. I'm using Xstream as my library. The Arraylist has like 215 users.
I tried StaxDriver and DomDriver. The Stax Driver result was same as empty Xstream constructor, but Dom was even worse.
XStream xstream = new XStream();
xstream.alias("Zakaznici", ListZakazniku.class);
try {
PrintWriter out = new PrintWriter("Zakaznici.xml");
out.write(xstream.toXML(ListZakazniku.zakaznici));
}catch (Exception e){
e.printStackTrace();
}
public class ListZakazniku {
public static ArrayList<Zakaznik> zakaznici = new ArrayList<>();
public ListZakazniku(){
zakaznici= new ArrayList<Zakaznik>();
}
public void setZakaznici(ArrayList<Zakaznik> zakaznik){
this.zakaznici.clear();
this.zakaznici = zakaznik;
}
public static ArrayList<Zakaznik> getZakaznici() {
return zakaznici;
}
public void add(Zakaznik elbow){
zakaznici.add(elbow);
}
and Zakaznik is pretty basic object with username, password, id....
the cut was like
</Zakaznik>
<Zaka
I don't know what's wrong with it. Im looking forward to any suggestions :)
Your list should not be static, also slightly modified your printing code. An approach like this will work fine:
#XStreamAlias("listZakazniku")
public class ListZakazniku {
private List<Zakaznik> zakaznicis;
public ListZakazniku() {
zakaznicis = new ArrayList<Zakaznik>();
}
public void add(Zakaznik user) {
zakaznicis.add(user);
}
#XStreamAlias("zakaznik")
private static class Zakaznik {
private String user;
private String pwd;
public Zakaznik(String user, String pwd) {
this.user = user;
this.pwd = pwd;
}
}
public static void main(String[] args){
XStream xstream = new XStream();
xstream.processAnnotations(ListZakazniku.class);
ListZakazniku ll = new ListZakazniku();
ll.add(new Zakaznik("user1", "pwd1"));
ll.add(new Zakaznik("user2", "pwd2"));
try {
try (PrintWriter out = new PrintWriter("Zakaznici.xml")) {
out.println(xstream.toXML(ll));
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Output:
<listZakazniku>
<zakaznicis>
<zakaznik>
<user>user1</user>
<pwd>pwd1</pwd>
</zakaznik>
<zakaznik>
<user>user2</user>
<pwd>pwd2</pwd>
</zakaznik>
</zakaznicis>
</listZakazniku>
Don't forget the processAnnotations-call for each annotated class! (also, your Zakaznik is not an internal static class I guess like in my example above, this was just to squeeze in the complete code..)
I have a messages.properties file that contains all string messages used in my application.
I would like to bind these messages to a java class fields and use directly in other classes.
Can this be achieved without using NLS? By some approach in javafx? Because I do not want to add eclipse dependency in UI classes.
Java provides property file reading capability right from the box. You can do adjustment to suit your actual use-case.
For example:
public final class Messages {
private Messages() {
loadFile();
}
private static final class ThreadSafeSingleton {
private static final Messages INSTANCE = new Messages();
}
public static Messages getInstance() {
return ThreadSafeSingleton.INSTANCE;
}
private final Properties props = new Properties();
private void loadFile() {
InputStream is = null;
try {
is = new FileInputStream("messages.properties");
props.load(is);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public String getMessage(String key) {
if (key == null && key.isEmpty()) return "";
return props.getProperty(key);
}
}
Edit
In order to use these values as if it is a constant, you need to pretty much make everything static:
public final class Messages {
private Messages() {} // Not instantiable
private static final Properties props = loadFile(); // Make sure this static field is at the top
public static final String FOO = getMessage("foo");
public static final String BAR = getMessage("bar");
private static Properties loadFile() {
final Properties p = new Properties();
InputStream is = null;
try {
is = new FileInputStream("messages.properties");
p.load(is);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return p;
}
public static String getMessage(String key) {
if (key == null && key.isEmpty()) return "";
return props.getProperty(key);
}
}
Be warned again, the Properties field must always be the top-most field declared in the class, because the class loader will load the fields top-down for all static fields whose value is computed at runtime (i.e. set by a static method).
Another point, this example does not handles what happens if the file is not file - it simply returns a Properties that has no value.
I'm looking to try and create a Java trivia application that reads the trivia from separate question files in a given folder. My idea was to use the run() method in the FileHandler class to set every text file in the folder into a dictionary and give them integer keys so that I could easily randomize the order at which they appear in the game. I found a simple chunk of code that is able to step through the folder and get the paths of every single file, but in the form a Path class. I need the paths (or just the names) in the form a String class. Because I need to later turn them into a file class (which excepts a String Constructor, not a Path). Here is the chunk of code that walks through the folder:
public class FileHandler implements Runnable{
static Map<Integer, Path> TriviaFiles; //idealy Map<Integer, String>
private int keyChoices = 0;
public FileHandler(){
TriviaFiles = new HashMap<Integer, Path>();
}
public void run(){
try {
Files.walk(Paths.get("/home/chris/JavaWorkspace/GameSpace/bin/TriviaQuestions")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
TriviaFiles.put(keyChoices, filePath);
keyChoices++;
System.out.println(filePath);
}
});
} catch (FileNotFoundException e) {
System.out.println("File not found for FileHandler");
} catch (IOException e ){
e.printStackTrace();
}
}
public static synchronized Path getNextValue(){
return TriviaFiles.get(2);
}
}
There is another class named TextHandler() which reads the individual txt files and turns them into questions. Here it is:
public class TextHandler {
private String A1, A2, A3, A4, question, answer;
//line = null;
public void determineQuestion(){
readFile("Question2.txt" /* in file que*/);
WindowComp.setQuestion(question);
WindowComp.setAnswers(A1,A2,A3,A4);
}
public void readFile(String toRead){
try{
File file = new File("/home/chris/JavaWorkspace/GameSpace/bin/TriviaQuestions",toRead);
System.out.println(file.getCanonicalPath());
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
question = br.readLine();
A1 = br.readLine();
A2 = br.readLine();
A3 = br.readLine();
A4 = br.readLine();
answer = br.readLine();
br.close();
}
catch(FileNotFoundException e){
System.out.println("file not found");
}
catch(IOException e){
System.out.println("error reading file");
}
}
}
There is stuff I didn't include in this TextHandler sample which is unimportant.
My idea was to use the determineQuestion() method to readFile(FileHandler.getNextQuestion).
I am just having trouble working around the Path to String discrepancy
Thanks a bunch.
You can simply use Path.toString() which returns full path as a String. But kindly note that if path is null this method can cause NullPointerException. To avoid this exception you can use String#valueOf instead.
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Path path = Paths.get("/my/test/folder/", "text.txt");
String str = path.toString();
// String str = String.valueOf(path); //This is Null Safe
System.out.println(str);
}
}
Output
\my\test\folder\text.txt