Refer to class outside jar/war file - java

Is it possible that we keep our jar/war file running and one class file in the same directory which can be referred from jar/war? The requirement is I want to keep some common code in single file which can be referred by multiple running jars/wars and I don't have to re-deploy application if I can successfully just change the class file.

I would go for this question here: How should I load Jars dynamically at runtime?
And them try the answers from jodonnell, chris and allain-lalonde depending on how do you want to access these class files, if by URL or by file path, and if you want to use JAR files or CLASS files.
In any case you should try and see it for yourself if it fits your needs and is acceptable by your employer standards. At certain point, we need to think out of the box. Don't worry if one or other user dislikes this or that approach. This community if meant for ask and receive answers on how to do it, and not to not do it.

Related

Read a file from same folder as JAR file but still read resources folder when loading from IDE

I've been trying to make jar application that can read a csv file in the same directory as it. This is, however, proving difficult as my means for accessing the file currently is:
InputStream is = getClass().getClassLoader().getResourceAsStream(filename);
Which works for my program running in the IDE and for my tests but doesn't work when I run the program from the compiled jar file. I have no idea how to get it to work for both. I seriously can't understand this path stuff, it seems like there are a million ways to do it and only one of them work for only one specific scenario.
I've been trying to make jar application that can read a csv file in the same directory as it.
Ah, there's your problem. That just isn't a thing.
There are only 2 types of files:
Application Resources
These are read only, and are as much part of your app as your class files are. It is not in any way relevant to think about 'editing' them - that's not the kind of thing they are. It is reasonable to assume that if this resource is somehow missing, the app is as corrupt / misinstalled as it would be if class files are missing.
For this, you use .getResource and .getResourceAsStream. And note that getClass().getClassLoader() is wrong, you want MyClass.class.getResource and then add a slash if you want to go from root (because getClass() potentially breaks when you subclass, and going via classloader is [A] just typing for no reason, and [B] breaks in bootload scenarios. MyOwnClassName.class.getResource never breaks, so, always use that).
This asks java to look in the same place class files are and nowhere else. Your class files are inside the jar files, and not next to them, therefore, it won't find a text file that is sitting next to jar files.
it does not make sense that it does work during development: That means you shoved a file inside the resources folder, which is equivalent to having a CSV file inside the jar file. You must have gone out of your way to tell your build system to do weird things. Don't do that.
If that CSV file is not intended to be user editable it should be inside the jar file and not next to it: That makes it an application resource. Examples of application resources:
You have a GUI, and you need to store the icon files and splash screen art and such someplace.
You ship static data with your app, such as a table of all US states along with the zipcodes they use (could be a text or csv file for example).
Templates of config files. Not config files themselves.
DLLs and the like that you need to unpack (because windows/linux/mac isn't going to look inside jars for them).
You're a webapp and you want to ship the HTML static files along with your webapp.
If this is what your CSV file is, the fix is to put it in the jar, not next to it, then load it with MyClass.class.getResource(name).
Config files and project files
For example:
For a rich text editor (like, say, LibreOffice Writer), the .odt files representing your writings.
Save games for a game.
A config file, which can be edited by the user, or is edited by your own app in a 'preferences' dialog. This stores for example whether to open the app full screen or not, or authentication info for a third party API you're using.
These should not be in the jar, should not be loaded with .getResource at all, and should not be in src/main/resources in the first place.
They also should not be next to your jar! That's an outdated and insecure model (the idea that editable files sit in the same place the app itself sits): A proper OS configuration means that an app cannot write to itself which is most easily accomplished by having it be incapable of writing to its directory. Some OSes (notably, windows) did this wrong for a while.
For example on windows, your app lives in C:\Program Files\MakorisAwesomeApp\makori.jar, and the data files for it live somewhere in C:\Users\UserThatInstalledIt\Documents\MakorisAwesomeApp.
oh linux, your app might be /usr/bin/makori and the data lives somewhere in the home dir. Config data might live in /etc/.
You don't "ship" your config files, you instead make installers that create them. You can do this part in-app by detecting that the relevant config file does not exist, load in a template (that is a resource, shipped inside your jar, loaded with getResource), and write it out, and tell the user to go look at it and edit it.
I really want a CSV file next to my jars!
Well, that's wrong, so, there are no libraries that make this easy. When you want to do silly things its good that APIs don't make that easy, right?
There are really hacky ways to do this. You can use .getResource to get a URL and then 'parse' this. This breaks the classloader abstraction concept (because in java, you can write your own classloaders and they can load from anywhere, not just files or entries in jars), but you can ask for 'yourself' (MyClass.class.getResource("MyClass.class")), pull the URL apart and figure out what's happening - does it start with file://? Then it is a file, so turn it into a j.i.File object, and go from there. Does it start with jar://? find the !, substring out the jar part, and now you know the jar. Make that a java.io.File, ask for the parent dir, and look there for the CSV.
You have to write all this. It's complicated code that is hard to test. You should not do this.

Reload existing class file dynamically for Java Application

Scenario
I am working on a big application consist of hundred of class files. As part of giving a patch to fix the issue in production set up, we generally give a jar file. This jar file contains the class file(s) which includes a fix and put inside one patch path(This is the path which is used to put the patches/fixes as jar file). In the production set up, we recommend to restart the application. As part of restart , application first looks the class files from patch path and then from the other path where all the class files are present. So this way first classes from patch path is loaded.
Expectation
Now instead of restarting the application, i want to reload the class file so that restart of application can be avoided. I checked in net and found the following:
We can use customize/dynamic class loader as well. I think this is also not full proof way of doing it.
URLClassLoader is also one of the option.
If we use customize class loader, then we have to load all the application class files using this because class file can refer to another class file if it is loaded from the same class loader. This is what i read from net. If yes, then i think this option is not valid. right ?
After checking all the above options, i still feel the above options are not good enough to load the existing class file (which is getting used in running application as well) at run time.
So question arises that is there any full proof possibily to replace the class file at run time for java application.
if Yes, Could you please guide in this regard.
Also, if this kind of requirement or question is already answered properly(I didn't find any good link), please redirect
NOTE: I think OSGi is also one option. But i feel not possible in such a big application since it will requires lot of changes which i want to avoid.
Please suggest.

Java: Accessing files that are in the same directory as your source file

How do i access a file that is in the same directory as my source file? I have seen it done in a tutorial and it was extremely simple, but any searches I conduct on the subject are too broad. any help? i.e.
doSomething("file.xml")
How do I access a file relative to the source file i am working with? i haven't seen how to do this, but since it would be an acceptable solution for the first question, here it is: i.e.
doSomething("src/com.package.file.xml")
I really just want a platform independent way to access files in my project. I know its probably a duplicate but please don't hate me.
Generally, you shouldn't
Files stored in the src directory (especially in Eclipse) won't be accessible at when the application is build and deployed.
Netbeans will package these files as part of your Jar when you build it, Eclipse requires you to these files stored in a separate "resources" directory within the project.
At this point, they become known as "embedded resources" and can no longer be accessed like a normal file, but instead, need to be loaded via the resources functionality available in your class.
For example.
To access the resource in com/package/file.xml, you would typically use some thing like...
getClass().getResource("/com/package/file.xml");
This will return a URL which represents the reference to the resource. If it's more confidnent, you can also gain an InputStream directly to the resource using something like...
getClass().getResourceAsStream("/com/package/file.xml");
Which will return an InputStream to the named resource...
This all of course, assumes that the resource can be found ;)

Save something into JAR

I have a java app, that needs to save and load user settings. I want to save them in a file located in the JAR file, how could I achieve this?
That's not possible. Rather consider using java.util.prefs.Preferences which is designed for exactly this purpose. See also this little guide.
This is not a sensible course of action.
A JAR file is basically just a ZIP file. To rewrite its contents you need to extract them in full, make changes as needed and then write them to a new file that replaces the old one.
If the program that is going to do this is the same one as that contained in the JAR file, this becomes impossible as the file is write protected during execution.
You'd be better advised to store your configuration elsewhere.
That is not the way to store preferences as others said.
If you has to do it that way then :
Locate the JAR from code: How to get the path of a running JAR file?
Unjar the contents to temp folder
Modify in the temp folder
Jar temp folder to the new JAR file.
To add to what Kris said, most security experts will tell you that it's generally a bad security practice to allow end-user applications to modify their own code. What you're asking for would require that.

Getting directory path to .class file containing main

Is it possible to get the path to my .class file containing my main function from within main?
URL main = Main.class.getResource("Main.class");
if (!"file".equalsIgnoreCase(main.getProtocol()))
throw new IllegalStateException("Main class is not stored in a file.");
File path = new File(main.getPath());
Note that most class files are assembled into JAR files so this won't work in every case (hence the IllegalStateException). However, you can locate the JAR that contains the class with this technique, and you can get the content of the class file by substituting a call to getResourceAsStream() in place of getResource(), and that will work whether the class is on the file system or in a JAR.
According to http://www.cs.caltech.edu/courses/cs11/material/java/donnie/java-main.html, no. However, I suggest reading $0 (Program Name) in Java? Discover main class? , which at least gives you the main class .
What do you need it for? If you need it to get hold of any files that are in the same directory, that's what Class.getResourceAsStream() is for.
That looks more like an end-user issue to me. Also consider the possible need to run multiple instances of any given application, and preventing users from doing so is going to become a major annoyance.
If the problem is with temporary file conflicts, then just make sure all your temporary files have unique names. This, as I understand it, is the most common reason people feel a need to prevent multiple instances of their applications from running.
P.S.: The java.io.File.createTempFile() methods are ideally suited for preventing temporary file conflicts because they automatically generate unique filenames.

Categories

Resources