I am having issues with properties file when I try to make my standalone Java aplication a runnable jar.
I have 2 properties file, depending upon the machine where its running one gets initialized.
Inside eclipse it was working fine. I was using:
Properties configProps = new Properties();
....
if(machine1)
....
configProps.load(Config.class.getResourceAsStream("machine1.properties"));
else
configProps.load(Config.class.getResourceAsStream("machine2.properties"));
It was working as Config.java and properties were in the same package.
On top of that I have log4j properties located on the root of the project.
That is also not working whne i made Jar.
How to handle the current sutuation.I know putting properties file outside jar is good idea.
How do I accomplish this.
Please help.
Putting the properties file outside of the jar is only a good idea if you need to write to that property file (it's for configuration). Given your naming, I assume it is for configuration.
For reading only, your method is fine if the properties file is properly being packaged in the Jar. Is it? Have you peaked at the contents using jar tf MyJar.jar? Does it show your properties file at the correct path?
Where to store configuration files is a broader issue. Here's a good SO article that examines a few aspects of it (namely where to put it): What is the proper way to store app's conf data in Java?
It seems to me you want to choose a location (see the above article). Once you've done that, the first time the application is run you should load the default properties from your Jar file as you are trying to do, then immediately save them to the location you've chosen. Then, and afterwards, read from and write to that location instead. You will need to use a FileInputStream/FileOutputStream.
Try adding a manifest to your JAR's META-INF with Class-Path set appropriately.
Related
If I use a file calling it directly:
FileInputStream fileInputStream = new FileInputStream("SR02_pattern.xls");
( the file is in \apv\main-app directory), it won't be deployed, and of course, it won't be seen when the project will be run on the server.
If I put the file in the /apv/main-web/WEB-INF/classes/ directory, it will be deployed and I can call it by
InputStream inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("SR02_pattern.xls")
when the project is deployed on the server, but that line won't read the file in the case the class was run from the test.
Probably, the place where the file will be looked for by getResourceAsStream("SR02_pattern.xls"), is set by some system properties and I can use them, but I don't know which properties can help.
How can I read the file in both cases by the same code without passing it as a parameter into the class?
There are many answers on SO for either of those cases, but I couldn't find one that works for both. The default paths for both cases are different.
Of course, I can put the file in both places, and in case the file is not in the first folder, look it in the second, as I am doing now, but upkeeping two copies is prone to errors and I desire to use better style.
You should use this.getClass().getResourceAsStream('/SR02-pattern.xl') for all parts in test as well in production code. The / defines the root directory for the resources.
The files you would like to read should be located in src/main/resources. This will result in the final war package at the location WEB-INF/classes.
I want to set the log4j configuration file path/other folder paths that can be used across other class files, without hard-coding the folder path.
Rightnow, I have set the variables as Environment variable. But It can only be modified if I launch Eclipse. How do I set this variable in such away that anyone (doesn't want to launch Eclipse) can modify it, from outside. Also, it will be used in test configurations. So it's better to not hard-code it and have all the file paths etc. easy to refactor.
final static String log4jpath = System.getenv("LOG4J_PATH");
Paraphrasing a comment:
[How to get value from] outside of the Java program such as a separate file, that contains all other filepaths?
That is called a configuration file.
It is often a properties file, similar to a Log4j configuration file, but it can be any types of file, e.g. XML, JSON, YAML, ...
To identify a single such file, you can use:
An environment variable (like you are right now)
A system property (more common)
A specifically named file in the current directory
...
The entries in that file will identify all the values you really want.
For example, Spring, which is a populate Java framework, will look for configuration values in many places. See 24. Externalized Configuration for full detail, but here is a summary of the most common ones:
Command line arguments, e.g. java -jar MyApp.jar --foo=bar
Java System properties, e.g. set using -Dfoo=bar on the command-line
OS environment variables, e.g. SET foo=bar (Windows) or export foo=bar (Linux)
Application properties outside of your packaged jar, i.e. relative to current directory.
Name and location can be overridden on command-line.
config/application.properties
config/application.yaml
application.properties
application.yaml
Soni, If you want to put the log4j configuration file in one place so that everybody can access. Follow the steps.
Create a project with some name and inside src/main/resources folder keep the log4j configuration file.
Create a jar file which must contain this log4j configuration file.
Use this created jar file wherever it is required. Log4j will automatically use the configuration for desired logging. If you want, you can distribute this jar file to anybody who wants to use it.
The above option is if you do not want to change the configuration file.
Now if there is a situation where someone wants to modify the configuration file.
In this case, simply put the configuration in any project classpath, means inside resource folder. As long as log4j jar files are there in the classpath and configuration files. It will log everything.
However, if you want, you can extend the functionality of Log4j by passing configuration as an object. You can refer below the link to access pro grammatically.
https://howtodoinjava.com/log4j/how-to-programmatically-configure-appenders-in-log4j/
I have added all file and folder paths inside the properties file (example config.properties) and then used it inside the testsetup method by InputStream input = new FileInputStream("Path to//config.properties");
Properties prop = new Properties();
prop.load(input);
System.setProperty("log4j2.configurationFile", prop.getProperty("log4j.path"));
this way, all files/folder paths can be modifies from outside and there's no need to set environment variable from inside the project.
I have a need to load an external file into the classpath using Play Framework 2.3 (Java)
Stipulations:
The external file cannot live inside my Play app (i.e. the /conf and /lib directories, etc. are not an option)
The file needs to be a .properties or a .conf file so I can specify property values
Here's my scenario:
I have a custom JAR that has some code which is looking for a specific file (let's call it myproperties.properties) in the classpath when being used. The way that I'm attempting to find myproperties.properties is by doing this inside a class that resides inside that custom JAR:
ClassLoader classLoader = com.my.package.MyCustomJavaClass.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("/path/to/myproperties.properties");
I have access to change the properties file name and the path to it inside the JAR.
My Play Framework App (using Java) has this custom JAR in it's /lib folder, so it gets automatically added to the classpath (this is tested and works correctly). My Play App calls MyCustomJavaClass when it first loads the / route (index route), so the class loader and input stream code above gets kicked off when I hit my play app in the browser.
Problem:
I have not been successful in my attempts to load /path/to/myproperties.properties into the classpath when starting the Play App in a way that my code in the custom JAR can see it.
I've been attempting to start play with the classpath command like so in an attempt to feed the JVM the external file:
activator start -J-classpath "-J-classpath:/path/to/myproperties.properties"
I'm adding -J-classpath; to the beginning of the path in an attempt to copy everything that's currently in the classpath and then just adding my single, external file. However, doing this doesn't seem to be working (i.e. my inputStream is null).
Questions:
Am I doing the activator start -J-classpath command correctly when starting the play app? Other variations in an attempt to copy the existing classpath first were not allowing the play app to start, but this command at least starts my app.
Reference (Specifying additional JVM arguments): https://www.playframework.com/documentation/2.3.x/ProductionConfiguration
What are some other ways that I could possibly get this done? I've explored overriding the application.conf file using activator start -Dconfig.file=/path/to/application-override.conf and putting my properties inside the new application-override.conf file. However, it doesn't seem to put that file into the classpath for MyCustomJavaClass to find using the Class Loader. Maybe I'm doing this command incorrectly as well?
Is it possible that somehow the Play Framework classpath is separate from the classpath that my custom JAR is seeing? I've been under the assumption that it's all in one JVM and classpath.
here's the solution I came up with, hopefully it helps someone else out there:
in my "upper environments" (AWS servers) where my play app is deployed, I put an application-override.conf file in the conf folder in the play framework app directory
the application-override.conf is the exact same as my application.conf but I have some custom properties in both whose values are different in each environment that the play app lives on
my play framework app is in a git repo, which is cloned on each upper environments, so I added application-override.conf to the .gitignore (I don't want it checked it to the repo so it only lives on the servers)
when starting the play app, I now use activator start "-Dconfig.trace=loads -Dconfig.file=conf/application-override.conf". this will override the application.conf file with application-override.conf and application-override.conf will be in the JVM classpath that play uses to run the app (since it's in the conf directory). -Dconfig.trace=loads spits out more logging to let you know if the .conf file was loaded properly or not; it's not a necessary flag if everything is working properly.
on the java side, in my custom JAR, I can now do the following:
Properties properties;
InputStream stream;
ClassLoader classLoader = com.my.package.MyCustomJavaClass.class.getClassLoader();
// first, look for application-override.conf in the classpath (upper environments)
stream = classLoader.getResourceAsStream("application-override.conf");
// if null, check for application.conf (local environment)
if (stream == null) {
stream = classLoader.getResourceAsStream("application.conf");
}
properties = new Properties();
properties.load(stream);
stream.close();
other notes:
I thought about doing a symlink/softlink in the conf directory and put the application-override.conf file somewhere else on my environment, but prior to Play 2.4, you can't have symlinks in the conf directory, so I just put the actual application-override.conf file in the conf folder
The application-override.conf file has different property values for each "upper environment", otherwise I would have just delivered a single override file to the git repo. And in the custom JAR, I didn't want to put in logic that looked for varying file names like dev-override.conf, pre-prod-override.conf, prod-override.conf, etc. I wanted a single upper environments override file.
I didn't have success with the -classpath=/path/to/myproperties.properties or -J-classpath=/path/to/myproperties.properties commands in conjuction with activator start. nor did I have success with attempting to append to the classpath, e.g. activator start -J-classpath=-J-classpath:/path/to/myproperties.properties or other similar combinations
going the route of putting properties in an application-override.conf file actually killed two birds with one stone for me because I've been wanting to make some environment specific changes by having overriding .conf files on each of my environments as well as custom properties
the HOCON format of the .conf files required me to put double quotes around my property values due to the nature of my property values. when reading in those properties in Java, the quotes were still there for me, so I had to do an str.replace("\"","") when reading in those properties
Currently i have placed the Displaytag.properties in 'src' directory, and it is working fine. Is it posssible to have this file on some different location like src/comp/bre/sub/config ?
From the docs for the DisplayTag library:
For the whole web application, create
a custom properties file named
"displaytag.properties" and place it
in the application classpath.
Displaytag will use the locale of the
request object to determine the locale
of the property file to use; if the
key required does not exist in the
specified file, the key will be loaded
from a more general property file.
So in your case make sure your build scripts (or IDE) copy your displaytag.properties file from src/comp/bre/sub/config the onto the classpath.
In an IDE this is normally as simple as specifying that a particular directory contains source code. In ANT just make sure the displaytag.properties file ends up in your /WEB-INF/classes.
Find the code which loads this properties file and add the new path. You can also place it in a folder yourProject/src/resources/ and add it to the classpath. Therefore, your properties file will be placed in the binary folder once the code will be compiled.
What is the best way to store and load application level properties in Java.
Is there anything simulare to .net where I would just put something in the app.config
<appSettings>
<add key="emailAddress" value="me#example.com" />
</appSettings>
And then retrieve it like this:
string AdminEmail = ConfigurationManager.AppSettings["emailAddress"];
Do I have to load properties files into file streams and such? seems like unnecessary work.
I have tried this:
Properties props = new Properties();
FileInputStream fis = new FileInputStream("myProps.properties");
props.load(fis);
fis.close();
But this is give me a java.io.FileNotFoundException exception. Where does the properties file need to go to in relation to the class?
The Preferences API provides this functionality. It has many warts, but if you are looking to do this in an OS-agnostic fashion, this is the only way to accomplish this using the standard Java runtime libraries. You can of course always write your own OS-specific code to meet your needs. Yes, you can write simple code to load a properties file, but the location of that file can become a problem across multiple operating systems. I assume since you are writing a desktop app in Java, you care about OS portability. Otherwise Java might not be the best choice for a desktop app.
If you use a FileInputStream like that, your path is relative to the current directory of the OS, which usually is the startup directory.
If you instead use the Java built in resources mechanism (as described in the API, getResourceAsStream() et al), the path will be relative to the location of your class. With this approach you can also load resources from within jars and even over networks (for Applets for instance). The concept which is used is a sort of virtual filesystem, which is called the 'classpath' in Java jargon. There is a devx article covering it a litte more in detail.
In short, this sort of code works well:
Properties prop = new Properties();
//with properties in the same dir as current class
prop.load(getClass().getResourceAsStream("my.properties"));
//with properties in the root dir of your jar, or in base of classpath
prop.load(getClass().getResourceAsStream("/my.properties"));
You will need to add error handling...
Typically it will attempt to load from the application's current directory, which can vary depending on how you run it. You should be able to determine this at runtime by doing:
String currentFolder = System.getProperty("user.dir");
The file path it would be looking for in that case is relative to where you started your java application from. This is not where the main class is or the jar file but where you called Java from. If you are starting your application with a script that calls Java, then it is that directory.
Say for example, you application is bundled in a jar file 'app.jar'. Put 'myProps.properties' in the same directory and run 'java -jar app.jar' from that directory. It should find your properties file that way.
You can use Properties with a ResourceBundle. I use this in a application to store labels, buttons and messages in different languages
First you create a properties file, like test.properties. It´s a text file and inside it you put your information like this:
propertyname=value
In your case
emailAddress=me#example.com
email2=blablabla#example.com
and so on...
To get this properties in the code, create a ResourceBundle object with the name of your property file to call the properties.
ResourceBundle rb = ResourceBundle.getBundle("test");
To get an specific value from a properties file, just call the ResourceBundle
String value = rb.getString("emailAddress");
This way, the String named value contains the value of the property named "emailAddress", located in the test.properties file
String value2 = rb.getString("email2");
Likewise, the String named value2 contains the value of the property named "email2", located in the test.properties file
When you do not specify an absolute path, the one chosen is the current one.
It's not exactly what you asked, but if you want to use XML files as configuration, you could have a look at Apache Commons Configuration