I have created a Java program to compare scripts saved as files in the version management tool to those loaded in our database. It's a simple program, runs through start to finish and outputs to the console when it finds a discrepancy. Now I want to load the database URL, username and password as well as the location of my files from a .properties file.
I did assume that if I put the file on the classpath it would be visible from my Java program:
Properties values = new Properties();
try
{
File checkPackages = new File("myfile.properties");
if(!checkPackages.exists()) throw new FileNotFoundException();
values.load(new FileReader(checkPackages));
}
catch(FileNotFoundException fnfe) {}
I also wanted to save this whole program to a .jar file so that it would be that bit more usable. Unfortunately, the only way I have found to reference the .properties file is to have it in the directory where I am running java.exe. The PATH or the CLASSPATH don't seem to apply??
I found an Oracle site about the .jar file's Manifest file as I was hoping there'd be an answer there, but the Class-path: element in the manifest only seems to refer to .jar files that are not in the .jar (and not .properties files that are!)
Questions:
Is there any way to wrap the .properties file into the .jar file so that my user doesn't have to know it is there?
Is there any way to wrap the Oracle driver .jar into the app's .jar so my user doesn't have to know it is there (Oracle says this needs 'custom code')?
TIA
You can get the resources in your classpath (even when sealed in the JAR) by using the ClassLoader#getResource() and ClassLoader#getResourceAsStream() methods.
For example:
Properties values = new Properties();
values.load(ThisClass.class.getClassLoader().getResourceAsStream("myproject.properties"));
// umm, don't forget to close the stream, this code is just an example usage
Note that storing the username and password to any database in a program is considered a heavy security risk.
One of the appraoch can be 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 ... -Dmyproject.properties=/path/to/my.app.properties
my.package.App
Fetch the property in your code as mentioned here:
String propPath = System.getProperty( "myproject.properties" );
final Properties myProps;
final FileInputStream in = new FileInputStream( propPath );
try
{
myProps = Properties.load( in );
}
finally
{
in.close( );
}
Well, I would recommend to encrypt the sensitive data (username, password, url in this case) with public and private keys rather than hiding it. It is afterall not hard to deflate any jar file (which is essentially a zip format) and trace the .properties file
Related
I'm looking to add a product version number to appear in my .jar file information. Currently I'm using Maven in my Spring boot project for API Rest.
I have read a lot of solutions about the manifest versioning. There you have to decompress and access to the META-INF/MANIFEST.MF to check the Implementation-Version. That's too tedious for what I'm looking for.
Like for a .exe. where you can found it under right mouse click -> details -> "product version" or simply checking on File Version column as shown on image. Example of a file version description.
Also I read that JAR file is a file format based on the popular ZIP file format and is used for aggregating many files into one. Kinda that I'm looking to add a file version to .zip, but I want to ask anyway if that is possible.
Regards, Gaspar.
A JAR file itself can't have a version. But you're using Maven, and that means you can already access the Maven version:
try (InputStream inputStream = getClass().getResourceAsStream("/META-INF/maven/<groupId>/<artifactId>/pom.properties")) {
Properties properties = new Properties();
properties.load(inputStream);
// available properties:
// - artifactId=xxx
// - groupId=xxx
// - version=xxx
}
Note that this often doesn't work in unit tests (especially when run from IDEs) because the files are only added to the JAR file.
Just include a text file anywhere in your jar. Build systems of all stripes make this trivial. Then write in your code that you read out this text file with the version, and show it on screen.
In maven, gradle, etc, to include a plain text file in the jar, just put it in src/main/resources/version.txt and it gets included automatically.
To read it in java:
public class Main {
public static String getVersion() {
try (var in = Main.class.getResourceAsStream("/version.txt")) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}
}
This:
Asks the classloader to load version.txt using the same systems that load .class files.
reads that inputstream fully, and turns it into a string using the UTF_8 encoding.
Uses try-with-resources because, it's a resource, you have to do that if you don't want leaks.
I want to distribute a Java application that connects to an external database using a Java properties file. My issue is that once my project is exported as a Jar file (and then as an EXE using Launch4j) in a different place than my project's root folder, the connection to my database fails and most of my pictures are not loaded.
Regarding just the connection, I have tried several things to read the connection properties written in an external file, which is located in a source folder :
The code :
I also tried to let the property file in the root folder of my project: both way work when running the project, but fail when launching the jar or the exe.
First I thought it was just because of the exportation of my project, that maybe failed due to some wrong settings. But I am started to think that I may have a wrong understanding on how to import resources into a Java project, even thought I followed several topics on that subject on Stackoverflow.
So :
What is the best way to include properties files in a way that makes it possible to export them in a Jar/exe file ?
Or, should these files be included after generating the Jar, by referencing them when producing the exe ? How would that be ?
As the connection file contains some sensible data (ie. the password to connect to the database), I hoped there was an official way to keep that file protected from unwanted access after exporting the Jar/exe file.
Thank you a lot for helping.
I can provide more code and pictures if needed.
Resources (as in a jar) are not File (on the file system). Use
getClass().getResourceAsStream("/conf/connexxion.properties");`
For that place the conf under /resources.
String configFile = "conf/connexion.properties";
InputStream inputStream = this.class.getClassLoader().getResourceAsStream(configFile);
Properties props = new java.util.Properties();
if (inputStream != null) {
props.load(in);
}else{
System.out.println("File not found");
}
(or)
Properties prop = new Properties();
URL url = ClassLoader.getSystemResource("/conf/connexion.properties");
if (url != null)
prop.load(url.openStream());
}
I have created a java program that other testers will use to help with their testing. I will be sending them a zip file with the .jar, a readme.txt, and main.properties.txt file.
The main.properties.txt file is a template for the testers to input their DB access credentials. They will update the main.properties file with their db cred's and then attempt to run the .jar from the terminal or command line. The issue I am running into is this. My program needs this updated main.properties.txt file so it can create the connections to our DB's.
What instructions do I need to give in my readme so my program can successfully find the main.properties.txt? Does the main.properties need to be in the same directory as the .jar? Can the testers just create a file on their desktop or documents folders to put the .jar and main.props?
The other question I have is how do I pass this file to my program once its ran from the terminal? Currently it is really easy, because the main.props is part of my program and I can just do something like
Properties prop = new Properties();
FileInputStream in = new FileInputStream("src/main/resources/main.properties");
prop.load(in);
in.close();
But now main.properties is not part of the project anymore. I don't know how to change the code above so that it can find the text from a directory on the local. The location in which they wish to put their main.properties is out of my control so writing a static path will not work. Please help!
There are many ways, I'll show you two.
You need a File object that points to the main.properties file. Then you create a stream on this object new FileInputStream(File) , as you already did by using a String.
The problem of course is to get a relative path to main.properties.txt which works on all systems, regardless where the jar-File is located.
1. Desktop
In this case the main.properties.txt is located at the users desktop. Here is how you access it:
File desktop = new File(System.getProperty("user.home"), "Desktop");
File target = new File(desktop, "main.properties.txt");
Alernativly, if you plan to distribute configuration and property files that do not require user interaction, you may want to use locations like Temp or Documents (Windows).
2. Relative to the jar
Probably one of your best options. Assume the target is in the same folder than the jar-File (or at least in a fix structure relative to the jar). Here is how you access it (related question: how-to-get-the-path-of-a-running-jar-file):
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
File jarDir = jarFile.getParentFile();
File target = new File(jarDir, "main.properties.txt");
I'm developing a Dynamic Web Project in Eclipse. I created a .properties file for store database details (Username, Password etc.). I added it by right clicking on the project and New -> File . I used the Java util package Properties class. But it does not working. I can not retrieve any property from the file. Here is the code I used,
Properties prop = new Properties();
try {
prop.load(new FileInputStream("database.properties"));
String db = prop.getProperty("database");
String userName = prop.getProperty("dbuser");
String password = prop.getProperty("dbpassword");
} catch (IOException ex) {
ex.printStackTrace();
}
Is there something wrong or Is there any particular place where I should put properties file.
What you did is correct, ie right clicking the project and new--file.You have to Put your properties where you start your jvm from. Please look into the attached image. The properties file is marked in red. Look if your properties file is also located something like this.
Also add this in your code to find out where to put your file:
System.out.println(new File(".").getAbsolutePath());
For more details please follow this link- FileNotFoundException when using java properties file
Normally, you make sure the properties file is in the project runtime classpath (e.g. WEB-INF/classes) and then load it using either the System classloader or the property file handler's classloader, i.e. (Freehand typing from memory -- NOT COMPILED)
try{
Properties p = new Properties();
InputStream in = MyPropertyHandler.getClass()
.getClassLoader()
.getResourceAsStream("com/package/props/database.properties");
p.load(in);
catch(IOException e){
e.printStackTrace(System.err);
}
I'm betting you aren't pointing at the correct location. Make sure you're properties file is in the correct place. Using that code, I believe it is looking for ${CURRENT_WORKING_DIR}/database.properties, which is the case of a web app in eclipse is WEB-INF/classes (i think).
You should instead be using the more portable java.util.Properties#load(InputStream) with the result of javax.servlet.ServletContext#getResourceAsStream(String).
Try to give absolute path or relative path to the proprty file, also check this propery file path has been add to source folders or not, if not it will not be copied to your classes folder. (Right cclick on project , check java build path under source tab.
You should have .properties file in same package as class that is using it.
Or better, read properties file with getResourceAsStream method (otherwise you can have some problem later when you'll have file in .war archive).
InputStream inputStream =
getClass().getClassLoader().getResourceAsStream("database.properties");
I'm loading a prop and saving it
File propfile=new File(getClass().getResource("credentials.properties").toURI());
prop.load(new FileInputStream(propfile));
prop.setProperty("a", username);
prop.setProperty("c", password);
prop.setProperty("b", pbKey);
prop.store(new FileOutputStream(propfile), null);
When i normally run this in netbeans its fine, when its bundled into .jar file it throws
Caused by: java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.(Unknown Source)
now when i use
getClass().getResourceAsStream("credentials.properties");
i can read the file , but i can't save the file unless i use the .toURI()
as in -> Storing changes in .properties file that has been read via getClass().getResourceAsStream
so when i use toURI() and when i run it (jar file) it would cry out saying the URI is not hierarchical
and when i use getResourceAsStream , i couldn't save the file
what should i do?
the properties file is in same package as class is in.
If you only need to load the properties, you shouldn't be using File at all - you should use getResourceAsStream.
If you need to save the properties back again, you can't easily have them in a jar file. You'd need to rebuild the jar file each time you save - ick!
If you really need both, you might want to consider having a file which is created the first time you need to save changes: when loading, use the file if it's present, but use the version in the jar file otherwise.
EDIT: If you're building a desktop application and these are basically user preferences, you should look into the Preferences API. Also be very careful if you're storing passwords... avoid doing so if you possibly can.
Try:
File userFile = new File(System.getProperty("user.home"), "myProgram.properties");
if(userFile.exists()) {
prop.load(new FileInputStream(userFile));
} else {
prop.load(getClass().getResourceAsStream("credentials.properties"));
}
prop.setProperty("a", username);
prop.setProperty("c", password);
prop.setProperty("b", pbKey);
prop.store(new FileOutputStream(userFile), null);
(be aware that user.home does not work every time on every machine, but it should work next to every time.)