Reputation: 6039
I have a JAR file where all my code is archived for running. I have to access a properties file which need to be changed/edited before each run. I want to keep the properties file in the same directory where the JAR file is. Is there anyway to tell Java to pick up the properties file from that directory ?
Note: I do not want to keep the properties file in home directory or pass the path of the properties file in command line argument.
Upvotes: 152
Views: 238217
Reputation: 1596
One approach would be to add current directory in the classpath of your JAR using following entry in the META-INF/MANIFEST.MF file:
Class-Path: .
Then following code to load "system.properties" file will work seamlessly:
ResourceBundle systemPropertiesBundle = ResourceBundle.getBundle("system");
Upvotes: 0
Reputation: 27
File parentFile = new File(".");
String parentPath = file.getCanonicalPath();
File resourceFile = new File(parentPath+File.seperator+"<your config file>");
Upvotes: 1
Reputation: 9498
This works for me. Load your properties file from current directory
.
Attention: The method Properties#load
uses ISO-8859-1 encoding.
Properties properties = new Properties();
properties.load(new FileReader(new File(".").getCanonicalPath() + File.separator + "java.properties"));
properties.forEach((k, v) -> {
System.out.println(k + " : " + v);
});
Make sure, that java.properties
is at the current directory
. You can just write a little startup script that switches into to the right directory in before, like
#! /bin/bash
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $scriptdir
java -jar MyExecutable.jar
cd -
In your project just put the java.properties
file in your project root, in order to make this code work from your IDE as well.
Upvotes: 1
Reputation: 57
Here if you mention .getPath()
then that will return the path of Jar and I guess
you will need its parent to refer to all other config files placed with the jar.
This code works on Windows. Add the code within the main class.
File jarDir = new File(MyAppName.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String jarDirpath = jarDir.getParent();
System.out.println(jarDirpath);
Upvotes: 1
Reputation: 4000
So, you want to treat your .properties
file on the same folder as the main/runnable jar as a file rather than as a resource of the main/runnable jar. In that case, my own solution is as follows:
First thing first: your program file architecture shall be like this (assuming your main program is main.jar and its main properties file is main.properties):
./ - the root of your program
|__ main.jar
|__ main.properties
With this architecture, you can modify any property in the main.properties file using any text editor before or while your main.jar is running (depending on the current state of the program) since it is just a text-based file. For example, your main.properties file may contain:
app.version=1.0.0.0
app.name=Hello
So, when you run your main program from its root/base folder, normally you will run it like this:
java -jar ./main.jar
or, straight away:
java -jar main.jar
In your main.jar, you need to create a few utility methods for every property found in your main.properties file; let say the app.version
property will have getAppVersion()
method as follows:
/**
* Gets the app.version property value from
* the ./main.properties file of the base folder
*
* @return app.version string
* @throws IOException
*/
import java.util.Properties;
public static String getAppVersion() throws IOException{
String versionString = null;
//to load application's properties, we use this class
Properties mainProperties = new Properties();
FileInputStream file;
//the base folder is ./, the root of the main.properties file
String path = "./main.properties";
//load the file handle for main.properties
file = new FileInputStream(path);
//load all the properties from this file
mainProperties.load(file);
//we have loaded the properties, so close the file handle
file.close();
//retrieve the property we are intrested, the app.version
versionString = mainProperties.getProperty("app.version");
return versionString;
}
In any part of the main program that needs the app.version
value, we call its method as follows:
String version = null;
try{
version = getAppVersion();
}
catch (IOException ioe){
ioe.printStackTrace();
}
Upvotes: 169
Reputation: 2983
I have an example of doing both by classpath or from external config with log4j2.properties
package org.mmartin.app1;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.LogManager;
public class App1 {
private static Logger logger=null;
private static final String LOG_PROPERTIES_FILE = "config/log4j2.properties";
private static final String CONFIG_PROPERTIES_FILE = "config/config.properties";
private Properties properties= new Properties();
public App1() {
System.out.println("--Logger intialized with classpath properties file--");
intializeLogger1();
testLogging();
System.out.println("--Logger intialized with external file--");
intializeLogger2();
testLogging();
}
public void readProperties() {
InputStream input = null;
try {
input = new FileInputStream(CONFIG_PROPERTIES_FILE);
this.properties.load(input);
} catch (IOException e) {
logger.error("Unable to read the config.properties file.",e);
System.exit(1);
}
}
public void printProperties() {
this.properties.list(System.out);
}
public void testLogging() {
logger.debug("This is a debug message");
logger.info("This is an info message");
logger.warn("This is a warn message");
logger.error("This is an error message");
logger.fatal("This is a fatal message");
logger.info("Logger's name: "+logger.getName());
}
private void intializeLogger1() {
logger = LogManager.getLogger(App1.class);
}
private void intializeLogger2() {
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
File file = new File(LOG_PROPERTIES_FILE);
// this will force a reconfiguration
context.setConfigLocation(file.toURI());
logger = context.getLogger(App1.class.getName());
}
public static void main(String[] args) {
App1 app1 = new App1();
app1.readProperties();
app1.printProperties();
}
}
--Logger intialized with classpath properties file--
[DEBUG] 2018-08-27 10:35:14.510 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.513 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.513 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.513 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.513 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.514 [main] App1 - Logger's name: org.mmartin.app1.App1
--Logger intialized with external file--
[DEBUG] 2018-08-27 10:35:14.524 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.525 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.525 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.525 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - Logger's name: org.mmartin.app1.App1
-- listing properties --
dbpassword=password
database=localhost
dbuser=user
Upvotes: 0
Reputation: 177
I have a similar case: wanting my *.jar
file to access a file in a directory next to said *.jar
file. Refer to THIS ANSWER as well.
My file structure is:
./ - the root of your program
|__ *.jar
|__ dir-next-to-jar/some.txt
I'm able to load a file (say, some.txt
) to an InputStream inside the *.jar
file with the following:
InputStream stream = null;
try{
stream = ThisClassName.class.getClass().getResourceAsStream("/dir-next-to-jar/some.txt");
}
catch(Exception e) {
System.out.print("error file to stream: ");
System.out.println(e.getMessage());
}
Then do whatever you will with the stream
Upvotes: 3
Reputation: 7069
I did it by other way.
Properties prop = new Properties();
try {
File jarPath=new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String propertiesPath=jarPath.getParentFile().getAbsolutePath();
System.out.println(" propertiesPath-"+propertiesPath);
prop.load(new FileInputStream(propertiesPath+"/importer.properties"));
} catch (IOException e1) {
e1.printStackTrace();
}
Upvotes: 52
Reputation: 8411
There's always a problem accessing files on your file directory from a jar file. Providing the classpath in a jar file is very limited. Instead try using a bat file or a sh file to start your program. In that way you can specify your classpath anyway you like, referencing any folder anywhere on the system.
Also check my answer on this question:
making .exe file for java project containing sqlite
Upvotes: 3