piczaj
piczaj

Reputation: 414

Runnable Jar cannot find Resources and Other Libraries

I created a desktop app and I have run into a problem with my generated runnable jar. Everything works fine in the Eclipse environment, but when I generate the jar it only shows theswtcomponents (menu, tabs, etc..). The other libraries location is a blank area (library to generate gallery). The same does not appearset ToolBar(containing buttons with images),GoogleMap.htmldoes not appear.

How can I correctly generate an executable jar that will include these external sources?

ToolBar image loading code :

folderSearchIcon = new Image(display, this.getClass().getResourceAsStream("images/search_folder.png"));

GoogleMap.html loading code :

File mapFile = new File("resources/GoogleMap.html");        
if(!mapFile.exists()) {
    System.out.println("File doesn't exist! " + mapFile.getAbsolutePath()); 
    return;
}

Generating runnable jar:

enter image description here

My app structure in Eclipse and generated jar structure:

enter image description here

Generated manifest :

Manifest-Version: 1.0
Rsrc-Class-Path: ./ swt.jar commons-imaging-1.0-SNAPSHOT.jar org.eclip
  se.nebula.widgets.gallery_0.5.3.201210262156.jar xmpcore.jar metadata
  -extractor-2.6.3.jar
Class-Path: .
Rsrc-Main-Class: geotagger.AppInit
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader

Upvotes: 12

Views: 19157

Answers (4)

Corey Byrum
Corey Byrum

Reputation: 148

Since exporting into a runnable jar essentially creates one file, the file/image/resource in your resources folder can no longer be found with FileReader because the file location is now non-existent..

Changing from using FileReader fr = new FileReader(resource_file_path) to loading with an InputStream, InputStream is = getClass().getResourceAsStream(resource_file_path) and then using an InputStreamReader to actually use the resource in other locations. Hope this helps.

Upvotes: 0

xxxxxxxxx
xxxxxxxxx

Reputation: 1019

As you can see here:

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getResourceAsStream(java.lang.String)

getResourceAsStream() looks for the file in the same package as the class from which it is called. Thus it will look for a file named "com/whatever/more/images/search_folder.png" inside the JAR, which of course won't exist, because the contents of the "resources" directory are directly put in the root of the JAR file by the JAR exporter.

Use http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#getResourceAsStream(java.lang.String) instead.

The second part: when you load the HTML will never work. You try to find a File named "resources/GoogleMap.html", but that will look outside of the JAR, in the working directory of your java program process. You should again use the previous function to load the HTML:

http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#getResourceAsStream(java.lang.String)

Upvotes: 3

DDRider62
DDRider62

Reputation: 833

I lost many hours on this same issue. If you created your runnable jar using the options in the "Export" functionality in Eclipse, it just won't work. At least it didn't for me. No matter what number of options I tried, nothing worked. When trying to read the resources, the resourceUrl would return null. Finally, I decided to create the runnable jar using Maven, and leave the Eclipse kind help aside. I needed to have the dependent jars in a separate lib folder. I created the runnable jar as explained in http://www.mkyong.com/maven/how-to-create-a-manifest-file-with-maven/ and the solution worked for me. Somehow, when Eclipse creates the runnable jar package, the resources cannot be read, even though they are present in the jar file. Hope this will help others.

Upvotes: 3

Ian Roberts
Ian Roberts

Reputation: 122364

For the toolbar image you need to add a slash, i.e. instead of

this.getClass().getResourceAsStream("images/search_folder.png")

you need

this.getClass().getResourceAsStream("/images/search_folder.png")

This is because, as explained in the JavaDocs, Class.getResourceAsStream resolves relative paths against the package of the class in question, so if this is a com.example.Foo then getResourceAsStream("images/search_folder.png") would look for com/example/images/search_folder.png inside your JAR. Prepending the slash would make it look for images/search_folder.png instead, which is what your screenshot suggests you need.

You will need to use a similar trick for the GoogleMap.html - you can't load items from inside a JAR using java.io.File, but you could use this.getClass().getResource("/GoogleMap.html") to get a java.net.URL pointing to the HTML file inside your JAR.

Upvotes: 9

Related Questions