Java Jar file: use resource errors: URI is not hierarchical
Asked Answered
Z

6

88

I have deployed my app to jar file. When I need to copy data from one file of resource to outside of jar file, I do this code:

URL resourceUrl = getClass().getResource("/resource/data.sav");
File src = new File(resourceUrl.toURI()); //ERROR HERE
File dst = new File(CurrentPath()+"data.sav");  //CurrentPath: path of jar file don't include jar file name
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst);
 // some excute code here

The error I have met is: URI is not hierarchical. this error I don't meet when run in IDE.

If I change above code as some help on other post on StackOverFlow:

InputStream in = Model.class.getClassLoader().getResourceAsStream("/resource/data.sav");
File dst = new File(CurrentPath() + "data.sav");
FileOutputStream out = new FileOutputStream(dst);
//....
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) { //NULL POINTER EXCEPTION
  //....
}
Zoosperm answered 13/4, 2012 at 15:54 Comment(0)
O
127

You cannot do this

File src = new File(resourceUrl.toURI()); //ERROR HERE

it is not a file! When you run from the ide you don't have any error, because you don't run a jar file. In the IDE classes and resources are extracted on the file system.

But you can open an InputStream in this way:

InputStream in = Model.class.getClassLoader().getResourceAsStream("/data.sav");

Remove "/resource". Generally the IDEs separates on file system classes and resources. But when the jar is created they are put all together. So the folder level "/resource" is used only for classes and resources separation.

When you get a resource from classloader you have to specify the path that the resource has inside the jar, that is the real package hierarchy.

Owe answered 13/4, 2012 at 16:32 Comment(12)
I have tried again your way (is my second code above), but when it is go through: in.read(buf) ---> I meet null point exception. :( @:resource is a folder in my project. it has same hierarchy with other package. So, I need I must include resourceZoosperm
post the hierarchy of your projectOwe
But what if i really NEED an "File" object... ?Duquette
You cannot have a File object because a resource is not necessary a file.Owe
Could you please provide more details on that? When is a ressource not a file?Forevermore
When the resource is located in a jar, for example, the single resource is a Jar Entry object (not a file on file system), and cannot be used to create an instance of java.io.File classOwe
@Owe ^ This is not true - see my answerIlia
it works for me without the slash: "data.sav" instead of "/data.sav"Farceur
@Farceur it depends on where you put your resource. You can use data.sav without the starting / if you put your resource file in the same package of your class file. But in the question the data.sav is in the root package so in that case he needs to prepend /.Owe
Just like TekTimmy: But what if I REALLY NEED a file ? I'm in a email sending process and we wanna join a logo file picture to email. The pict is in the jar and I have to give it to the datasource as a File, not an InputStream...Barringer
@JNGerbaux i also wanted a File object so i created temp File and copied content from InputStream to File object. using FileUtils.copyInputStreamToFile(inputStream, file);Trilemma
@VishalPatel that is the right approach if you need the fileOwe
S
29

If for some reason you really need to create a java.io.File object to point to a resource inside of a Jar file, the answer is here: https://mcmap.net/q/83336/-how-to-get-a-path-to-a-resource-in-a-java-jar-file

File f = new File(getClass().getResource("/MyResource").toExternalForm());
Sharondasharos answered 21/6, 2016 at 15:26 Comment(0)
I
11

Here is a solution for Eclipse RCP / Plugin developers:

Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
   URL resolvedFileURL = FileLocator.toFileURL(fileURL);

   // We need to use the 3-arg constructor of URI in order to properly escape file system chars
   URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
   File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
    e1.printStackTrace();
} catch (IOException e1) {
    e1.printStackTrace();
}

It's very important to use FileLocator.toFileURL(fileURL) rather than resolve(fileURL) , cause when the plugin is packed into a jar this will cause Eclipse to create an unpacked version in a temporary location so that the object can be accessed using File. For instance, I guess Lars Vogel has an error in his article - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/

Ilia answered 30/5, 2014 at 11:4 Comment(4)
What is Platform class? Some non-rt library needed?Telium
@AndreyP this solution is for eclipse rcp plugin developers. I would recommend to try getResourceAsStream(...) approachIlia
In my maven-built RCP E4 application, jar-bundled binary files need to be extracted and opened. Your solution finally enabled me to do so and open file.getAbsolutePath() in the OS default browser.Depriest
Thanks ! This answer was very helpful, since I got a bug with FileLocator.resolve. I could create the File object directly with : File f = new File(FileLocator.toFileURL(resolvedFileURL).toURI());Helping
M
1

I got a similiar issues before, and I used the code:

new File(new URI(url.toString().replace(" ","%20")).getSchemeSpecificPart());

instead of the code :

new File(new URI(url.toURI())

to solve the problem

Martainn answered 25/1, 2019 at 3:22 Comment(0)
S
0

While I stumbled upon this problem myself I'd like to add another option (to the otherwise perfect explanation from @dash1e):

Export the plugin as a folder (not a jar) by adding:

Eclipse-BundleShape: dir

to your MANIFEST.MF.

At least when you export your RCP app with the export wizard (based on a *.product) file this gets respected and will produce a folder.

Stillbirth answered 10/3, 2014 at 16:32 Comment(0)
J
0

In addition to the general answers, you can get "URI is not hierarchical" from Unitils library attempting to load a dataset off a .jar file. It may happen when you keep datasets in one maven submodule, but actual tests in another.

There is even a bug UNI-197 filed.

Jacquejacquelin answered 12/5, 2017 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.