How should resources in a compiled jar be accessed? - java

First of all, I have read through many S.O. questions regarding this topic and I have tried the things suggested in them.
Here is my situation. I am writing a Java app using the Processing framework and I'm in the final stages where I need to begin thinking about packaging the app. A jar file that is executable from the command line is what I'm attempting to build using the Export feature in Eclipse.
The structure of my project looks like this:
src/
multiple packages/
libs/
jar files and natives
data/
fonts and images
config/
json files
When I export the jar file and uzip the jar to inspect it's contents, I find that the contents of these dirs have been dumped in the top level of the .jar.
Which looks like this:
.jar
packages
jar files
fonts
json files
So, when I attempt to load a config file with something like:
BufferedReader reader = new BufferedReader( new FileReader( path ) );
Everything works just file when I run the app in Eclipse. But the jar file throws a FileNotFoundException.
Many of the questions that I've seen on S.O. regarding problems like these recommend using using class.getClass().getResource() or class.getResourceAsStream(). I have tried both of these using relative paths and just the file name as in:
class.getResource( 'config.json' );
class.getResources( 'cfg/config.json' );
class.getResourceAsStream( '../../config.json' );
All of these methods return null, when run from either Eclipse or the jar using:
java -jar myjarfile.jar
I am also open to using an Ant file. In fact, I'm now using the Ant file generated by the export feature to build the jar. If there is something I can add to that to add the directories into the jar that would be great too.

To reach resources in the root, prepend a / to the path. If not, you do it relative to the current package, which is usually only useful if the resource is physically next to the class in your sources too.
So use class.getResourceAsStream("/config.json"); to reach config.json in the root of the jar.
Also note that jars-inside-jars are not directly supported.

Your .jar file should just include the directories related to the "package" for the compiled code. You might be referencing a .war structure with /lib /WEB-INF etc. and this is different.
If your package structure is:
com.yourco.authentication
And your class in Login
Then your jar should be
/com/
/yourco/
/authentication/
Login.class
you then need the .jar in your classpath for the env to run via command line.
I see you note it works in Eclipse which likely has environment settings and imported required libs, etc. so hard to tell exactly. If your packages/ folder includes the compiled java code, I'm unsure if that'll work when referenced externally, thus suggesting you start your packages in the root folder.

Related

Create Java projects without eclipse?

Is there any way I can create Java projects using a simple text editor? Not an IDE like eclipse?
I want to be able to create .jar files without the assistance of an IDE, I have all the JDK commands installed already on my computer (such as javac)
I'd like to know what file structure I need, how I need to arrange my class files, what compilation steps I need to go through etc. to be able to create jar files.
Yes, completely doable (just not much fun once the project gets bigger).
I suggest if it's not a throwaway project, use a build tool like Maven or Gradle to manage your build process, so that you don't need to assemble classpaths and resources yourself, but still retain full control of the build and test lifecycle, without IDEs. This comes at a complexity cost, of course, but once it's set up life becomes easier.
See also How can I create an executable JAR with dependencies using Maven? or the Gradle docs about creating JARs
I'd highly recommend the standard Maven source directory layout too (src/main, src/test etc) as it's both commonplace and makes for easy integration with the above tools.
Follow the below steps to create a jar file
Compile the java source using javac
Create a manifest file (if main exists) to identify main class
Use the below command to create a jar file
jar -cvfm *.class
Yeah. You can create your project structure without an IDE. But it's time consuming and you have to do everything.
To talk about creating JAR, you don't want any extra software. You can use jar utility, which comes with JDK.
Here are steps to create jar:
Compile classes which you want to in jar
Create manifest file (.mf). It's needed if you want to make jar as executable. If you want to bundle classes only together, then no need. (eg. Dependency jar)
Go to command prompt and execute following command "jar cvf MyJarName.jar *.class". Make sure java is set in environment path and you're inside the directory of classes.
cvf means "create a jar; show verbose output; specify the output jar file name.
That's all. If you want to include any folders inside jar then you can use folder name in above command after classes and it must be separated by space.
Example: jar cvf TicTacToe.jar TicTacToe.class audio images

Create a jar file using compiled class files and an existing MANIFEST.MF file

Is it possible to take existing .class files and a MANIFEST.MF to create a jar file?
Is there a library that can create a "valid" jar-file? I tried it manually and it didn't work (using 7zip).
ERROR: "Invalid or corrupt jar file"
If everything has been compiled before, it should (in my understanding) theoretically work, if you create a new zip file, put all the files in it in the original structure and then rename it to "jar".
My idea is to program something like this with java code. A solution where I could add a file to an existing jar, would also be ok.
If you're interested in why I want to use this, look at my initial question: Compile javacode out of a running java accpilaction - on a system that hasn't JDK installed
Well Jar -cf
Try the jar command in $JAVA_HOME/bin
$JAVA_HOME is the path to you JRE/JDK installation

How to make jar files that draw from a source folder

I've been wanting to make executable jar files with java lately. When executing my code with Eclipse it works perfectly. But when I use Eclipse to export the same code as a runnable jar, Most of my jars work except the ones that draw from separate source folders.
The jar will be made but when launched it will try and open and then just say to check to console for possible errors. I try and run the jar through the console with the command "java -jar test.jar". and It says it cannot access the jar. Any Ideas? Btw Im on a macbook pro osX. Thank you!!
picture of where my files are within eclipse
If you have a file you want to store in a jar and access from there, you don't really have a Java File any more. Look at Class.getResourceAsStream() and Class.getResource() - the first can give you an InputStream to the (used-to-be) file, the second returns a URL and can be used for things like images. Note that the file being accessed can be accessed relative to the package/folder location of the class or relative to a classpath root (by putting "/" at the front of the resource name ("/resource/funny.jpg")).
When you execute the jar from a command line, be aware that you have a thing called the "default directory"; it is a folder in which your commands execute by default. If your jar is not in the default directory, you have to specify a valid folder path to your jar to execute it.

Load files External To The Distribution Jar

I have written a Java program which I package and run from a JAR file. I need to have some user-changeable configuration files which are simply text lines of:
key = value
format. To load these files I used the class described here. When I run my program through Netbeans IDE all works fine as I have included the directory where I store the configuration files in the Project properties.
The problem comes when I build my application into a JAR file. As I want the configuration files to be user-editable I keep them OUTSIDE of the JAR but in the same directory but now when I run my application from the command line it cannot find the configuration files. If I manually add the files to JAR file at the ROOT folder then all is well.
So how can I tell Java to look outside of the JAR for my loadable files? The -classpath option has no effect.
That's because the way you are loading them requires that they be inside the .jar when running from a jar, or inside the project directory if not; it's relying on the classloader to tell it where to find the file.
If you want to open a file outside the .jar, you need to just open it as a File and read it in.
One of the ways we've approached this is to take the external filename as an option on the command line (e.g. java -jar myJar.jar -f filename). This allows you to explicitly state where the file is located. You can then decide whether or not to also look in a default location, or inside the .jar if the file isn't specified on the command line.
I resolved it by referring to this question. I Added the current directory to the MANIFEST file of the jar and it works.
Why is the -classpath option ignored in this case I wonder? Security?
I had the same problem and saw your post, but the answer in the end, was simple.
I have an application deployed via Java Webstart and am building it in Netbeans 7.3.
I have a properties file config.xml that will be updated during run time with user preferences, for instance, "remember my password".
Hence it needs to be external to the jar file.
Netbeans creates a 'dist' folder under the project folder. This folder contains the project jar file and jnlp file. I copied over the config.xml to the dist folder and the properties file was loaded using standard
FileInputStream in = new FileInputStream("config.xml");
testData.loadFromXML(in);
in.close();

The dreaded java.lang.NoClassDefFoundError

I've looked through many of the existing threads about this error, but still no luck. I'm not even trying to package a jar or use any third-party packaging tools. I'm simply running from within Eclipse (works great) and then trying to run the exact same app from the command line, in the same location it's built to (getting this error). My goal is to be able to zip up the bin folder and send it off to be run by someone else via a command line script. Some details:
It's a command-line app and I'm using the commons-lang-2.4.jar for string utilities. That is the file that cannot be located (specificaly "java.lang.NoClassDefFoundError: org/apache/commons/lang/StringEscapeUtils")
I have that jar in my lib folder and have added it to my build path in Eclipse via right-click "Build Path -> Add to Build Path"
The .classpath file looks correct and contains the reference to the jar, but I assume that file is only used by Eclipse (contains this line: <classpathentry kind="lib" path="lib/commons-lang-2.4.jar"/>)
Could this be related to the Eclipse working directory setting? I have some internal template files that I created that are under src/templates, and the only way I can seem to get those to be seen is by setting the project working directory to AppName/src. Maybe I should be putting those somewhere else?
Let me know if any additional info would help. Surely this is something simple, but I've wasted too much time on it at this point. This is reminding me why I originally left Java back in '05 or so...
A NoClassDefFoundError basically means that the class was there in the classpath during compiletime, but it is missing in the classpath during runtime.
In your case, when executing using java.exe from commandline, you need to specify the classpath in the -cp or -classpath argument. Or if it is a JAR file, then you need to specify it in the class-path entry of its MANIFEST.MF file.
The value of the argument/entry can be either absolute or relative file system paths to a folder containing all .class files or to an individual .jar file. You can separate paths using a semicolon ;. When a path contains spaces, you need to wrap the particular path with doublequotes ". Example:
java -cp .;c:/path/to/file.jar;"c:/spacy path/to/classes" mypackage.MyClass
To save the effort of typing and editing the argument in commandline everytime, use a .bat file.
Edit: I should have realized that you're using an Unix based operating system. The above examples are Windows-targeted. In the case of Unix like platforms you can follow the same rules, but you need to separate the paths using a colon : and instead of an eventual batch file, use a .sh file.
java -cp .:/path/to/file.jar:"/spacy path/to/classes" mypackage.MyClass
Are you specifying the classpath to java on the command line?
$ java -cp lib/commons-lang-2.4.jar your.main.Class
The classpath setting you are setting in Eclispe are only for the IDE and do not affect how you application is run outside the IDE. Even if you use the Eclipse Functionality to export your application as an executable jar file there is no out of the box way to package all the jars your application depends on.
If you have packaged you application into a jar file called myapp.jar then running a command like below will run the application with the jar you depend on, if you have more than one just add them separted by ; on Windows or : on Unix:
java -jar myapp.jar -cp .;c:/pathtolibs/commons-lang-2.4.jar
If you are just running the classes directly then either run the folder containing your .class files will also need to be on the path (though I assume it already is since you are able to run the program and get errors).
Consider File -> Export -> Runnable jar to create a jar file which can be invoked directly with
java -jar yourProgram.jar
There are several variants depending on your needs.
Eclipse does not move any of the jars in your classpath into the bin folder of your project. You need to copy the util jar into the bin folder. If you move it to the root of the bin folder, you might be able to get away without any classpath entries but it's not the recommended solution. See #BalusC's answer for good coverage of that.
Eclipse doesn't build executable java classes by default. Don't ask me why, but it probably has something to do with using their own tools.jar (somewhere in plugins/org.eclipse.core ?) so that Eclipse can run without a JDK.
You can usually go to your project bin directory and do:
java -cp . MyClass
But if you have external jars, Eclipse handles those internally in another weird way, so you'll need to add those too.
make sure your jar commons-lang-2.4.jar in classpath and not redudance.
I ever add jar file to my classpath, and have 2 file jar in my classpath. After I delete it, work smooth

Categories

Resources