Java program that worked in Eclipse fails when in a Jar - java

The following line of code:
SoyFileSet sfs = sfsBuilder.add(this.getClass().getResource("templates/mail.soy")).build();
works when run outside of a Jar but fails with a null pointer exception. Similar posts indicate that I should try getResourceAsStream but the add method wants a URL. So I think I have to convert the Stream to a URL but it is not clear to me exactly how to proceed.

sfsBuilder.add() also allows you to add content as CharSequence.
So, you can read the file yourself and add it to the builder.
Something like:
SoyFileSet sfs = SoyFileSet.builder().add(IOUtils.toString(this.getClass().getResourceAsStream("templates/mail.soy")), "file/path/for/messages").build();
IOUtils is from apache's commons-io project

This finally worked as follows:
{SoyFileSet sfs = sfsBuilder.add(this.getClass().getResource("/resources/templates/email.soy")).build();}
Not sure if this matters but in Eclipse the Runnable Jar was created using Package Required Libraries...

By the code you have posted, I guess templates/mail.soy is a file which belongs to your project, so it should be properly packed into the jar. However, the path should begin with a slash: /templates/mail.soy will match the following jar structure:
META-INF/
templates/
mail.soy
mypackage/
MyProgram.class

Related

Why does getResource return null

I'm trying to access a file in my project. But getResource method returns null.
This is how my project looks like:
Thread.currentThread().getContextClassLoader().getResource("assets/xxx.png"); //returns null
And how project folder in eclipse workspace looks like:
Why? I want to access files in my assets folder?
Edit
I created a jar file and this is content of the jar:
Solved
First of all, I've a lot of image files so I want to organize all them in a folder. I put the assets folder in src directory and finally I was able to access the files.
this.getClass().getClassLoader().getResource("assets/xxx.png");
There are lot of ways to add a resource to the jar file, you can put it in src, add as a resource if you use maven, ant etc... If you able to bundle whole directory then you should be able to use your original piece of code.
With the current structure you can use following piece of code.
Thread.currentThread().getContextClassLoader().getResource("/xxx.png").
Try using / prefixing.
Thread.currentThread().getContextClassLoader().getResourceAsStream("/xxx.png")
For someone struggling as me. For Maven just run mvn clean install.
After that Thread.currentThread().getContextClassLoader().getResource() should work.
Is there a reason you're using the the class loader of the current class? Something like this.getClass().getClassLoader().getResource("/xxx.png") should be more reliable.
Use the following code, it should work.
YOUR_CLASS_HERE.class.getClass().getResource( "/xxx.png" );
e.g.
Signin.class.getClass().getResource( "/xxx.png" );
Either Approach will work. its just Filepath issue.
Your Jar Structure shows no "asset" Folder
xxx.png file is directly in Jar File.
Try to remove "assets" from below line of code.
Thread.currentThread().getContextClassLoader().getResource("assets/xxx.png"); //returns null
Also, if you want to use "assets" folder in ur classpath, please ensure that your jar contains "assets" folder.

Opening a xml file from eclipse and from a .jar file in java

Yesterday, I had a problem because I couldn't manage to open a xml file (it owuld give me a FileNotFoundException) located in the ressources folder of my .jar file, which I managed to open on eclipse using the following lines of code. You can see my old problem here. This was my code with the problem :
File xmlFile = new File("ressources/emitter.xml");
ConfigurableEmitter emitter = ParticleIO.loadEmitter(xmlFile);
Someone told me it that one way was to use getClassLoader().getRessourceAsStream method to open a xml file in a .jar file that was exported
InputStream i= this.getClass().getClassLoader().getResourceAsStream("ressources/emitter.xml");
ConfigurableEmitter emitter = ParticleIO.loadEmitter(i);
Unfortunately, that solution only works when I export my project into a .jar file, so if I want to go back debugging my program, I have to take the old code that would only works on eclipse.
My question is: is there any better way to do this without having to change my code if I want to export it or if I want to debug it?
Thank you
edit :
Thank you all, it works perfectly fine now
my problem was that I put my ressources folder like that :
+project
+src
+ressources
+emitter.xml
InputStream i= this.getClass().getClassLoader().getResourceAsStream("/ressources/emitter.xml");
The above should work in both cases (Note is is /resources/.... This is assuming say your directory structure is below:
MyProject
+src
+ressources
emitter.xml
Place the file alongside your source files, then you can use the getResourceAsStream() method in both cases. Don't forget to update the path (which should be the package name of your class, but with slashes instead of dots).
My question is: is there any better way to do this without having to
change my code if I want to export it or if I want to debug it?
Yes, use Maven. Maven will handle that and it hooks into Eclipse beautifully (NetBeans too!) What you do is place the resource in src/main/resources and then you can have Eclipse run the test goal of the Maven project or you can just run mvn test from the command line. Another advantage of using Maven here is that you can also have src/test/resources/emitter.xml which overrides the one in src/main with environment-specific test instructions and it won't affect your deployment.
InputStream i= getClass().getClassLoader().getResourceAsStream("ressources/emitter.xml");
or
InputStream i= getClass().getResourceAsStream("/ressources/emitter.xml");
(note the absolute positioning)
both work when the class is in the same jar, on the same class path.
In the jar the names must be case sensitive, but as the jar already works. Ensure that the ressources directory is on the class path too, or copied to the target directory.
As "ressources" is probably configured yourself (not named "resources" as in English), you probably need to add it to the build somehow.

Why does getResourceAsStream() work in the IDE but not the JAR?

I just want to read a file into my program. The file is located one directory above the working directory at "../f.fsh". So the following code runs correctly when I run it in the IDE
String name="../f.fsh";
InputStream is = getClass().getResourceAsStream(name);
InputStreamReader isreader=new InputStreamReader(is);//CRASHES HERE WITH NULL POINTER EXCEPTION
BufferedReader br = new BufferedReader(isreader);
but when I create a JAR file that has f.fsh zipped inside of it and run it, it crashes when creating the InputStreamReader, because the InputStream is null.
I've read a bunch of answers to questions about input streams and JAR files, and what I got out of it is that I should be using relative paths, but I am already doing that. From what I understand getResourceAsStream() can find files relative to the root of the project, that is what I want. Why does it not work in the JAR? What is going wrong, how can I fix it?
Does it have to do with the classpath? I thought that was only for including files external to the jar being run.
I have also tried, but still fail, when putting a slash in:
InputStream is = getClass().getResourceAsStream("\\"+name);
I looked at: How to get a path to a resource in a Java JAR file andfound that contents of a JAR may not necesarily be accesible as a file. So I tried it with copying the file relative to the jar (one directory up from the jar), and that still fails. In any case I'd like to leave my files in the jar and be able to read them there. I don't know what's going wrong.
You can't use .. with Class.getResourceAsStream().
To load a resource f.fsh in the same package as the class, use SomeClass.class.getResourceAsStream("f.fsh")
To load a resource f.fsh in a sub-package foo.bar of the package of the class, use SomeClass.class.getResourceAsStream("foo/bar/f.fsh")
To load a resource f.fsh in any package com.company.foo.bar, use SomeClass.class.getResourceAsStream("/com/company/foo/bar/f.fsh")
This is described in the javadoc of the getResource() method, although it lacks examples.
If .. works in Class.getResourceAsStream() while running from Eclipse, it's a bug in Eclipse. Eclipse and other IDEs implement custom class loaders to fetch resources from the project at runtime. It looks like the class loader implementation in Eclipse isn't performing all the necessary validations on input to getResourceAsStream() method. In this case the bug is in your favor, but you will still need to rethink how you structure your resources for your code to work in all cases.
it's mandatory that the name of the file is CASE SENSITIVE
it's mandatory to refresh (F5) the project explorer if the file is moved or copied outside Exclipse

Junit + getResourceAsStream Returning Null

Not sure how this is possible. I re-read up on getResourceAsStream and it's always returning null.
InputStream source = this.getClass().getResourceAsStream("test.xml");
Right next to test.java in the Finder (using OS X and Eclipse) is test.xml
I can open it in TextWrangler and view it as existing with data inside.
This is a Junit test if it makes any difference. I went and looked at existing Junit tests on our system and I'm using it in the exactly same manner as a working example (as in where the file is located and the code itself).
What small difference could there be preventing I assume getClass() from returning the right path?
It's not finding the resource on the classpath. If you are using junit and maven make sure the resources are copied on the target/test-classes by adding <include> file directive on <testResource> section
You can also find out the location of your class in the file system by using
this.getClass().getResource(".")
and checking to see if the resource is there
getResourceAsStream() is using the CLASSPATH, and as such it will load from wherever your classes are, not your source files.
I suspect you need to copy your XML to the same directory as your .class file.
In case you are using Maven, add this part to your pom.xml
<build>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
</build>
Your test.xml and other resource files must be located in src/test/resources
I always have problem with this method. Here are 2 links, which might be useful:
Describes diference between
getClass().getResource(); and
getClass().getClassLoader().getResource();
Simple utility which simplifies
these 2 approaches
I always experiment with adding "/" at the beginning or "./".
From my experience the best method is using FileInputStream. There is only one thing to remember (while using FileInputStream with Eclipse), with default settings, your working directory is set to projects root. You can always check where is your current directory (and what relative paths you need)using this piece of code.
Assuming test.xml is located right under your test root source folder, do this:-
InputStream source = this.getClass().getClassLoader().getResourceAsStream("test.xml");
I spent lot of time in this problem and it was missing me the following configuration:
Right-click on an eclipse project and select Properties -> Java Build Path -> Source and edit Included row and add *.properties (*.fileExtension)
try using classloader
InputStream source = this.getClass().getClassLoader().getResourceAsStream("test.xml");
Put test.xml in the src/main/resources (or src/test/resources).
File file = ResourceUtils.getFile("classpath:test.xml");
String test = new String(Files.readAllBytes(file.toPath()));
Try MyClass.getResourceAsStream().
Also try putting the test.xml in your classpath. For instance, in an Eclipse web project put text.xml in webcontent/WEB-INF/classes
From Java API:
http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getSystemResource(java.lang.String)
Find a resource of the specified name from the search path used to load classes. This method locates the resource through the system class loader
So the syntax will for instance be:
ClassLoader.getSystemResource("test.xml").toString();
Works like a charm!
Seems there are a lot of possible causes to this and mine was not found here. I figured out that my tests were no longer being detected/run by maven and this baeldung post also provided a lot of possible causes. My problem ended up being that at some point I altered the wrong pom and set my packaging to pom.
The test-compile step was being skipped completely and no new resources were ending up in the classpath. So, check your target/test-classes directory and make sure that your tests are actually compiling in the first place.
I got a Similar issue. The problem in my case was that getResourceAsStream() was working fine for the main Application code but giving Null in case of unit-test. The problem was that for the main Application code it was looking in the target/classes folder for the file but for the unit-test it was looking in the target/test-classes. I fixed the problem by adding my file in the test/resources folder.
Add the folder that your having your resource files in to the source folders of eclipse. Then the file should be automatically put in the bin directory.
You need to put the copy of your resource file to the test resources, in my example it is font file:
Then call next from your jUnit test:
public static InputStream getFontAsStream() throws IOException {
return Thread.currentThread().getContextClassLoader()
.getResourceAsStream("fonts/" + "FreeSans.ttf");
}
I had this problem with a Spring class. System.class.getResourceAsStream(...) worked in unit tests but not in Tomcat, Thread.currentThread().getContextClassLoader().getResourceAsStream(...) worked in Tomcat but not in unit tests.
Ulitimately I went with:
ClassUtils.getDefaultClassLoader()
.getResourceAsStream("com/example/mail/templates/invoice-past-due.html"))
I also found that once I did it this way, I did not need to have the path starting with a slash.

Netbeans Built .jar doesn't work with class file inside

I had problems while finding the path of file(s) in Netbeans..
Problem is already solved (checked answer).
Today I noticed another problem: When project is finished,
I have to execute the generated .jar to launch the program, but it doesn't work because an error occurs: NullPointer (where to load a file) when accessing/openning jar outside Netbeans.
Is it possible to open a file with the class file in Java/Netbeans which works in Netbeans and even in any directory?
I've found already some threads about my problem in site but none was helpful.
Code:
File file = new File(URLDecoder.decode(this.getClass().getResource("file.xml").getFile(), "UTF-8"));
The problem you have is that File only refer to files on the filesystem, not files in jars.
If you want a more generic locator, use a URL which is what getResource provides. However, usually you don't need to know the location of the file, you just need its contents, in which case you can use getResourceAsInputStream()
This all assumes your class path is configured correctly.
Yes, you should be able to load a file anywhere on your file system that the java process has access to. You just need to have the path explicitly set in your getResource call.
For example:
File file = new File(URLDecoder.decode(this.getClass().getResource("C:\\foo\\bar\\file.xml").getFile(), "UTF-8"));

Categories

Resources