I am trying to explore Apache commons configuration to dynamically load the property file and do modification in the file and save it.
I wrote a demo code for the same.
Code Snippet
package ABC;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
public class Prop {
public static void main(String[] args)
{
try {
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
System.out.println("null");
}
String absolutePath=propertiesURL.getPath();
PropertiesConfiguration pc = new PropertiesConfiguration(absolutePath);
pc.setReloadingStrategy(new FileChangedReloadingStrategy());
String s=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + s);
pc.setAutoSave(true);
pc.setProperty("key_account_sales", "Dummy");
pc.save();
System.out.println("Modified as well");
String sa=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + sa);
}catch(ConfigurationException ce)
{
ce.printStackTrace();
}
}
}
Although when I run the code multiple times, the updated value for the property is being properly shown but the changes are not seen in the Property file.
I tried refreshing the entire workspace and the project but still the property file shows the previous entry whereas this code displays the updated entry in console.
Why my property file is not getting updated?
Well I noticed that a new file with same name was formed inside bin
directory of my IDE workspace. This new file contains the required
changes.
However I still want that the old file should be updated with the new
value and instead of creating a new file, it should update in the old
file itself.
My property file is located inside a Web Application package say
Dem1
by the name of
Prop1.prop
I want to read this property file from in another class say
Reading.java
located inside another package
Dem2
, do changes in this same property file and show it to another user. It is a web application being deployed on an application server.
Even after using the absolute path in a simple file (main function) it is not reflecting the changes in the same file but updating it in new file.
I am doing a very slight mistake but can someone please help.
Using absolute path I am not able to make changes in the same property file in normal main method also. Please suggest.
New file in bin directory is created instead of updating the same file
in src folder.
You should be able to solve this using absolute paths. The PropertiesConfiguration class is finding your properties file somewhere on the classpath and only knows to write back to "d1.properties"; hence you have a file appearing in your bin directory.
The absolute path can be obtained by querying resources on the classpath. Something like the following:
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
// uh-oh...
}
String absolutePath = propertiesURL.getPath();
// Now use absolutePath
Related
I have written a project where some images are used for the application's appearance and some text files will get created and deleted along the process. I only used the absolute path of all used files in order to see how the project would work, and now that it is finished I want to send it to someone else. so what I'm asking for is that how I can link those files to the project so that the other person doesn't have to set those absolute paths relative to their computer. something like, turning the final jar file with necessary files into a zip file and then that the person extracts the zip file and imports jar file, when runs it, the program work without any problems.
by the way, I add the images using ImageIcon class.
I'm using eclipse.
For files that you just want to read, such as images used in your app's icons:
Ship them the same way you ship your class files: In your jar or jmod file.
Use YourClassName.class.getResource or .getResourceAsStream to read these. They are not files, any APIs that need a File object can't work. Don't use those APIs (they are bad) - good APIs take a URI, URL, or InputStream, which works fine with this.
Example:
package com.foo;
public class MyMainApp {
public void example() {
Image image = new Image(MyMainApp.class.getResource("img/send.png");
}
public void example2() throws IOException {
try (var raw = MyMainApp.class.getResourceAsStream("/data/countries.txt")) {
BufferedReader in = new BufferedReader(
new InputStreamReader(raw, StandardCharsets.UTF_8));
for (String line = in.readLine(); line != null; line = in.readLine()) {
// do something with each country
}
}
}
}
This class file will end up in your jar as /com/foo/MyMainApp.class. That same jar file should also contain /com/foo/img/send.png and /data/countries.txt. (Note how starting the string argument you pass to getResource(AsStream) can start with a slash or not, which controls whether it's relative to the location of the class or to the root of the jar. Your choice as to what you find nicer).
For files that your app will create / update:
This shouldn't be anywhere near where your jar file is. That's late 80s/silly windows thinking. Applications are (or should be!) in places that you that that app cannot write to. In general the installation directory of an application is a read-only affair, and most certainly should not be containing a user's documents. These should be in the 'user home' or possibly in e.g. `My Documents'.
Example:
public void save() throws IOException {
Path p = Paths.get(System.getProperty("user.home"), "navids-app.save");
// save to that file.
}
private void copyFile() throws IOException {
Path destination;
String currentWorkingDir = System.getProperty("user.dir");
File fileToCopy = component.getArchiveServerFile();
if (path.contains(File.separator)) {
destination = Paths.get(path);
} else {
destination = Paths.get(currentWorkingDir + File.separator + path);
}
if (!Files.exists(destination)) {
try {
Files.createDirectories(destination);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
FileUtils.copyFileToDirectory(fileToCopy, new File(destination.toString()));
}
}
Basically what I'm trying to do here is copying a file in some location using the path provided in the class's constructor. The logic is like this:
If the path has file separator, I consider it a full path and copy the file at the end.
If the path doesn't have file separator, I copy the file in the working directory from which the .exe file was launched.
So far, only the first option works (the full path). For some reason, the working directory option is not working and I can't figure out why.
UPDATE: If I just change the following line:
String currentWorkingDir = System.getProperty("user.dir");
to
String currentWorkingDir = System.getProperty("user.home");
It works. So I'm guessing the problem is coming from user.dir? Maybe at runtime, the folder is already being used and as a result, it can't copy the file into it?
The weird thing is, I don't have any exceptions or error, but nothing happens as well.
UPDATE 2: I think the problem here is that I'm trying to copy a file which is embedded in the application (.exe file) that I'm executing during runtime, and java can't copy it while the current working directory is being used by the application.
UPDATE 3:
Since this copy method is used in an external library, I had to come up with another way (other than logs) to see the content of system property user.dir. So I wrote I little program to create a file and write in it the value return by the property.
To my surprise, the path is not where my application was launched. It was in:
C:\Users\jj\AppData\Local\Temp\2\e4j1263.tmp_dir1602852411
Which is weird because I launched the program from :
C:\Users\jj\workspace\installer\product\target\
Any idea why I'm getting this unexpected value for user.dir?
I need to run a web-app on Tomcat, but it cannot read the txt files(from a relative paths as below) on Tomcat. However, it does work if I use a full path.
So I am wondering where can I put these txt files so that when Tomcat started, the app can successfully read the txt files from a relative path.
Currently, the project structure is as follows, the txt files is located on the same directory as src file in Project Explorer in Eclipse.
Project_Name
src
java files
EDGES.txt
NODES.txt
The code is as follows, I am appreciated if someone can give me an answer in details, since I am quite new to Java.
The code is as follows:
public class RouteingDao {
NodeJSONReader nodeInput = new NodeJSONReader("NODES.txt");
EdgeJSONReader edgeInput = new EdgeJSONReader("EDGES.txt");
...
}
The NodeJSONReader/EdgeJSONReader class is as follows:
public class EdgeJSONReader {
private EdgeEntity[] edgeEntity;
// constructor
public EdgeJSONReader(String JSON_FILE) {
edgeEntity = readEntityFromFile(JSON_FILE);
}
// load the JSON data from local file
public EdgeEntity[] readEntityFromFile(String JSON_FILE) {
try {
Reader reader = new FileReader(JSON_FILE);
Gson gson = new Gson();
edgeEntity = gson.fromJson(reader, EdgeEntity[].class);
}
...
}
}
If you are using a servlet, then access the servlet context and the getRealPath method.
this.getServletContext().getRealPath("WEB-INF/nodes.txt")
The relative path sent to getRealPath will be expanded to the location of the files for your web app. You can add any path you like, even to a hidden file in WEB-INF.
From a JSP you can use
${pageContext.servletContext.getRealPath("WEB-INF/nodes.txt")}
Be careful, this will be in the build directory, so any changes to nodes.txt will not be saved to the original file.
i want my jar file to access some files from itself. I know how to do this for BufferedImage but this doesn't work for other files. All i want is to extract some zips from my jar. i made a class folder in eclipse, put the zips inside and used
public File getResFile(String name){
return new File(getClass().getResource(name).getFile());
}
to get the File instance and extract it. it works fine in eclipse, but as soon as i export it to a jar it says
Exception in thread "main" java.io.FileNotFoundException: file:\C:\Users\DeLL\Desktop\BoxcraftClient\ClientInstaller.jar!\client.bxc (The filename, directory name, or volume label syntax is incorrect)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:220)
at java.util.zip.ZipFile.<init>(ZipFile.java:150)
at java.util.zip.ZipFile.<init>(ZipFile.java:164)
at Launcher.install(Launcher.java:43)
at Launcher.main(Launcher.java:33)
Im working to fix this already something like 6 hours and can't find a solution. Please help!
There is a reason why getResource() returns a URL, and not a File, because the resource may not be a file, and since your code is packaged in the Jar file, it's not a file but a zip entry.
The only safe way to read the content of the resource, is as an InputStream, either by calling getResourceAsStream() or by calling openStream() on the returned URL.
first check your class path using java System.out.println("classpath is: " + System.getProperty("java.class.path")); to see if the classpath has your jar file.
And then use the getclass().classloader.getResourceAsStream(name). See if the returned URL is correct. Call the method isFile() on the URL to check if the URL is actually a file. And then call the getFile() method.
Use one of these methods, from the class Class
- getResource(java.lang.String)
- getResourceAsStream(java.lang.String)
this.getClass().getResource(name);
this.getClass().getResourceAsStream(name);
Warning: By default it loads the file from the location, where the this.class, is found in the package. So if using it from a class org.organisation.project.App, then the file need to be inside the jar in the directory org/organisation/project. In case the file is located in the root, or some other directory, inside the jar, use the /, in from of the file name. Like /data/names.json.
Use Spring's PathMatchingResourcePatternResolver;
It will do the trick for both launching the package from an IDE or from the file system:
public List<String> getAllClassesInRunningJar() throws Exception {
try {
List<String> list = new ArrayList<String>();
// Get all the classes inside the package com.my.package:
// This will do the work for both launching the package from an IDE or from the file system:
String scannedPackage = "com.my.package.*";
// This is spring - org.springframework.core; use these imports:
// import org.springframework.core.io.Resource;
// import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage.replace(".", "/"));
for (Resource resource : resources)
list.add(resource.getURI().toString());
return list ;
} catch (Exception e) {
throw new Exception("Failed to get the classes: " + e.getMessage(), e);
}
}
Play 2.2.3. Windows 7.
public static Result menu() throws IOException {
String path = Play.application().resource("resources/menu.json").toString();
String content = Files.toString(new File(path), Charsets.UTF_8);
return ok(content).as("JSON");
}
Got an error:
... scala-2.10\classes\resources\menu.json The filename, directory
name, or volume label syntax is incorrect
Checking that path in file-system, I'm able to find my file there:
..\target\scala-2.10\classes\resources\menu.json
I'm able to find it there. Why play can't?
--
UPDATE:
I've just figured out I can not create files on C:\ root folder on my machine. That maybe the issue. But on other hand I'm not accessing root folder, and ad trying to get read only access. And I do have write access to that file on that path anyway.
As actually you want to use your menu.json file as a static asset you can put it i.e. into public/resources/menu.json file and then read it with simple:
<script>
$.get('#routes.Assets.at("resources/menu.json")');
</script>
or just directly by request:
http://localhost:9000/assets/resources/menu.json
To do what you want via controller you need to read the InputStream by classpath (remember that finally it will be archived into jar file!) but it need to be placed in conf folder i.e.: conf/resources/menu.json then from controller:
public static Result menuViaControllerJson() {
InputStream is = Play.application().classloader().getResourceAsStream("resources/menu.json");
return (is != null)
? ok(is)
: notFound();
}
Anyway you will get exactly the same result as for common Assets.at, so consider if it's worth of effort.
Edit: If you want to use this file as custom config just use HOCON syntax file i.e.: conf/ses.conf:
foo = "bar"
and in controller:
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
....
Config cfg = ConfigFactory.parseResources(Play.application().classloader(), "ses.conf");
debug("My 'foo' is configured as: " + cfg.getString("foo"));