Trouble With Java getResourceAsStream, confusion with how Packages work - java

I'm revisiting Java after briefly learning it in high school to work through the lwjgl git book. There's a section that kind of loses me where the fragment shader / vertex shader is supposed to be loaded, using the function 'getResourceAsStream'.
I've tried different approaches, and vainly tried to debug / print the locations where the JVM was searching for the file, but I'm kind of at a loss. I am very confused, but would also prefer understanding why this code doesn't work on my machine, and how to get it to work (with this package / class loading approach).
Since the classes both share the 'main' class, I thought the JVM would search starting there for a 'resources' folder. But this does not seem to be the case.
I do think it has to do with the package declarations, but I don't understand enough to proceed.
Here are the relevant files and locations... I tried to only include what I thought important.
// project-root/src/main/java/org/lwjglb/engine/Utils.java
package main.java.org.lwjglb.engine;
// other imports...
public class Utils {
public static String loadResource(String fileName) {
InputStream in = class.forName(Utils.class.getName()).getResourceAsStream(fileName);
// 'in' is null after this call
// other code...
}
}
// project-root/src/main/java/org/lwjglb/game/Renderer.java
import main.java.org.lwjgl.engine.Utils;
// other imports...
public class Renderer {
public void init() {
Utils.loadResource("/vertex.vs"); // fails
}
}
// project-root/src/main/resources/vertex.vs
// vertex shader code...
The issue is that the getResourceAsStream() call returns null, so the following code that depends on a valid result crashes with a java.lang.NullPointerException.
What path should I pass in to getResourceAsStream() so that it will not return null?

Assume the following directory structure:
|-- src
`-- test
|-- java
| `-- shaders
| `-- ShaderParser.java
`-- resources
`-- shaders
`-- fragmentShader.txt
The proper way to get the resource "fragmentShader.txt" from "ShaderParser.java" is:
Class clazz = Class.forName(TestUtils.class.getName());
InputStream in = clazz.getResourceAsStream("../../resources/shaders/fragmentShader.txt");
The ../ means "traverse upward one directory".
The path starts in the src/test/java/shaders/ directory so we use ../../ to traverse upward twice into src/test/ and then tack on the rest of our path resources/shaders/fragmentShader.txt.
It is important to remember that when using Class#getResourceAsStream(), it uses the package that the class resides in as the base directory. It ONLY uses relative paths because it is trying to load the resource using that class' ClassLoader. and will not work if supplied with a fully qualified path or a path starting at the project root.
Please refer to the documentation for more information.

I had erroneusly thought that Java had a reserved directory (e.g. 'resources') where it would look first to load files. Kind of similar to Flask in python.
However, I understand now that the class.getResourceAsStream() function either takes relative paths (to the current 'lowest' level package) or absolute paths (from the project's top-level root).
I had furthermore erroneously thought that I could try doing a relative path load, from one of the higher-level packages. As in, I'm in package main.java.org.lwjgl.engine.Utils, but when looking for the file main.resources.vertex.vs, I could start the search from the 'main' package and pass 'resources/vertex.vs' or 'resources/vertex.vs'. I don't know if this is possible, but it feels erroneous.
Instead, the solution is to pass the file location '/main/resources/vertex.vs'. This will start at the project-root, and correctly load the file.
I'm still confused as to how the lwjgl code worked, but I see that it could be possible that the classPath was set to 'main', so passing an absolute path could work.

Related

InputStream gives IllegalArgumentException for just the jar file [duplicate]

The line persistenceProperties.load(is); is throwing a nullpointerexception in the following method. How can I resolve this error?
public void setUpPersistence(){
final Properties persistenceProperties = new Properties();
InputStream is = null;
try {
is = getClass().getClassLoader().getResourceAsStream("src/test/samples/persistence.properties");
persistenceProperties.load(is);
}catch (IOException ignored) {}
finally {
if (is != null) {try {is.close();} catch (IOException ignored) {}}
}
entityManagerFactory = Persistence.createEntityManagerFactory(
"persistence.xml", persistenceProperties);
}
I have tried to experiment with this by moving the class that contains the method to various other locations within the application structure, and also by changing the line of code preceding the error in the following ways:
is = getClass().getClassLoader().getResourceAsStream("persistence.properties");
is = getClass().getClassLoader().getResourceAsStream("/persistence.properties");
is = getClass().getClassLoader().getResourceAsStream("/src/test/samples/persistence.properties");
is = getClass().getClassLoader().getResourceAsStream("other/paths/after/moving/persistence.properties");
But the error is still thrown every time the method is called.
Here is a printscreen of the directory structure of the eclipse project. The class containing the method is called TestFunctions.java, and the location of persistence.properties is shown:
**EDIT: **
As per feedback below, I changed the method to:
public void setUpPersistence(){
final Properties persistenceProperties = new Properties();
InputStream is = null;
try {
is = getClass().getClassLoader().getResourceAsStream("persistence.properties");
persistenceProperties.load(is);
}catch (IOException i) {i.printStackTrace();}
finally {
if (is != null) {try {is.close();} catch (IOException ignored) {}}
}
entityManagerFactory = Persistence.createEntityManagerFactory(
"persistence.xml", persistenceProperties);
}
I also moved mainTest.TestFunctions.java to src/test/java. Together, these all cause the following new stack trace:
Exception in thread "main" java.lang.NoClassDefFoundError: maintest/TestFunctions
at maintest.Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: maintest.TestFunctions
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 1 more
Short answer:
Move persistence.properties to src/main/resources, have both Main.java and TestFunctions.java in src/main/java, and use
getClass().getClassLoader().getResourceAsStream("persistence.properties");
to load the properties file.
Long answer with an explanation:
As others have hinted at - in a Maven project structure, you (typically) have two directory trees: /src/main and /src/test. The general intent is that any "real" code, resources, etc should go in /src/main, and items that are test-only should go in /src/test. When compiled and run, items in the test tree generally have access to items in the main tree, since they're intended to test the stuff in main; items in the main tree, however, do not typically have access to items in the test tree, since it's generally a bad idea to have your "production" code depending on test stuff. So, since Main.java depends on TestFunctions.java, and TestFunctions.java depends on persistence.properties, if Main is in src/main then both TestFunctions and persistence.properties need to be as well.
Two things:
First, try a path of test/samples/... or /test/samples/...
Secondly, and much more importantly, don't ever, ever, ever write this:
try {
// some stuff
} catch (IOException ignored) {}
All this says is: do some stuff, and if it goes wrong, then fail silently. That is never the right thing to do: if there's a problem, you want to know about it, rather than madly rushing on as if nothing had happened. Either do some sensible processing in your catch block, or else don't have the try/catch and add a throws IOException to your method signature so it can propagate upwards.
But at the moment, you're just sweeping things under the carpet.
ClassLoader.getResourceAsStream() loads resources as it does for loading classes. It thus loads them from the runtime classpath. Not from the source directories in your project.
Your class Main is in the package maintest, and its name is thus maintest.Main. I know that without even seeing the code because Main.java is under a directory named maintest, which is at directly under a source directory.
The persistence.properties file is directly under a source directory (src/test/resources). At runtime, it's thus at the root of the classpath, in the default package. Its name is thus persistence.properties, and not src/test/samples/peristence.properties. So the code should be
getClass().getClassLoader().getResourceAsStream("persistence.properties");
Nothing will ever be loadable from the samples directory, since thisdirectory is not under any source directory, and is thus not compiled by Eclipse, and is thus not available to the ClassLoader.
I will try to make it more Simple for this Question!
Here your main class is in src/main/java as you mentioned, so you should create another source for storing your properties file saying src/main/resources which you had already done and just store your properties file in this source, so in Run time it will directly refer this path and access the file,
You can add this piece of code as well to access the properties file
is = ClassLoader.getSystemResourceAsStream("your_properties_file");
and you can use load(is) accordingly.
To Conclude
If your main class is in src/main/java then you should keep your properties file in src/main/resources and use the respective snippet to load this.
OR
If your main class is in src/test/java then you should keep your properties file in src/test/resources and use the respective snippet to load this.
Your IDE works with two different scopes:
production scope: src/main/java + src/main/resources folders and
test scope: src/test/java + src/test/resources
Seems you are trying to execute you program from production scope, while persistence.properties file is placed into test scope.
How to fix:
Place your test into src/test/java or
Move persistence.properties into src/main/resources
InputStream is = this.getClass().getResourceAsStream("/package_name/property file name")
PropertyFileOject.load(is)
In my case error was due to maven was not treating my config folder inside src/main/java as source folder.
Recreated config package in src/main/java ..Copied files to it and re-compiled using maven. Files were there in target directory and hence in war. Error resolved.
I recently had the same problem and came upon the solution that I had to put my resources in a path the same way organized as where was getClass().getResourceAsStream(name) situated. And I still had a problem after doing that. Later on, I discovered that creating a package org.smth.smth only had created a folder named like that "org.smth.smth" and not a folder org with a folder smth and a folder inside smth... So creating the same path structure solved my problem. Hope this explanation is understandable enough.

Trying to compile Java source (could not find main class)

Trying to learn Java again and I cannot remember how I figured this out the first time around.
I have 3 classes; a GameLauncher, GuessGame, and Player. GameLauncher has my main method.
They are all packaged as chap02, I cannot remember if that is important to me yet.
I am compiling like this: javac GameLauncher.java GuessGame.java Player.java
running like this: java GameLauncher
I am getting this error: Could not find or load main class GameLauncher.
I know this is a ridiculous issue, but I have always had trouble with this kind of stuff. The actual programming and writing code I can pick up just fine, but dealing with these damn compilers always gets me. Any help would be appreciated. Thanks
package chap02;
public class GameLauncher {
public static void main (String[] args) {
GuessGame game = new GuessGame();
game.startGame();
}
}
Edit: The issue isn't with the actual code, the issue is with how I am compiling it.
When running the program, you have to run it form the correct directory. Remember, that you used packages, so you have the following package-structure
src
chap02
GameLauncher.java
GuessGame.java
Player.java
after compilation, you will find the corresponding .class-files in the chap02-folder. To start the game, you have run the following command from the src-directory:
java chap02.GameLauncher
Since you specified a package in the source code, you have to use the full qualified name, including the package, to which the class belongs.
EDIT as vefthym mentioned, you have to compile the code in the same way, running
javac chap02/GameLauncher.java
from the source-directory.
EDIT 2
"src" is the directory, where your src lies. I, for example, have my Code unter X:\JDK-Projects[Project-name]\src. You have to specify the full absolute path to the src-Directory or the relative path form the directory you are currently in.

Logic.class.getResource("effects\\newball.wav"); returns null

I've got the problem that the following code snip returns null:
System.out.println(Logic.class.getResource("effects\\newball.wav"));
I have a source folder in my project called effects. in this folder there's the referred file. I think there's a syntax error... Because THE FILE IS THERE. I must refer in this way (means with getResource) to my file because I will export it as jar later.
Thank you
Your effect directory should be a direct child of the src dir. Also in which case, you need a / to start the string path. So you would need this
System.out.println(Logic.class.getResource("/effects/newball.wav"));
ProjectRoot
src
effect
newball.wav
What I normally do using an IDE is just create a new package and name it whatever I want the file to be - in your case "effect". It's easier that way.
UPDATE
"I did it exatly so, but it still returns null"
It works fine for me
package stackoverflow;
public class Test {
public static void main(String[] args) {
System.out.println(Test.class.getResource("/effects/stack_reverse.png"));
}
}
Output: file:/C:/Android/workspace/StackOverflow/bin/effects/stack_reverse.png
Resource paths should use forward slashes, regardless of the filesystem on the machine you are using: try "effects/newball.wav"
See http://docs.oracle.com/javase/7/docs/technotes/guides/lang/resources.html (Under "resources, Names, and Contexts -- "The name of a resource is independent of the Java implementation; in particular, the path separator is always a slash (/).")

Error reading image from scala playn

I researched and looked into the PlayN game framework and I liked it a lot. I program in Scala and actually don't know Java but it's not usually a problem since they work together great.
I've set up a basic project in eclipse and imported all the libraries and dependencies. I even translated over the base maven project code. Here's the two files:
Zeitgeist.scala
package iris.zeit.core
import playn.core.PlayN._
import playn.core.Game
import playn.core.Image
import playn.core.ImageLayer
class Zeitgeist extends Game {
override def init (){
var bgImage: Image = assets().getImage("images/bg.png")
var bgLayer: ImageLayer = graphics().createImageLayer(bgImage)
graphics().rootLayer().add(bgLayer)
}
override def paint (alpha: Float){
//painting stuffs
}
override def update(delta: Float){
}
override def updateRate(): Int = {
25
}
}
Main.scala
package iris.zeit.desktop
import playn.core.PlayN
import playn.java.JavaPlatform
import iris.zeit.core.Zeitgeist
object Main {
def main(args: Array[String]){
var platform: JavaPlatform = JavaPlatform.register()
platform.assets().setPathPrefix("resources")
PlayN.run(new Zeitgeist())
}
}
The cool thing is it works! A window comes up perfectly. The only problem is I can't seem to load images. With the above line, "assets().getImage("images/bg.png")" it pops out
Could not load image: resources/images/bg.png [error=java.io.FileNotFoundException: resources/images/bg.png]
I've played around with the location of my resources file to no avail. I was even able to find bg.png myself with java.io.File. Am I doing something wrong? Is there something I'm forgetting?
Looking at the code of JavaAssetsManager, it looks like it is trying to load a resource and not a file. So you should check that your images are actually in the classpath and at the path you give ("resources/images/bp.png")
Alternatively, you can use getRemoteImage and pass a File URL. As you succeeded in using a java.io.File, you can just get the URL with method toUri of File (toUrl is deprecated).
This almost certainly doesn't work because you're doing this:
platform.assets().setPathPrefix("resources")
That means you're saying your source folder looks like this:
src/main/resources/resources/images/bg.png
src/main/resources/resources/images/pea.png
src/main/resources/resources/images
I imagine it actually looks like one of these:
src/main/resources/assets/images/bg.png <-- 'assets' the default prefix
src/main/resources/assets/images/pea.png
src/main/resources/assets/images
or:
src/main/resources/images/bg.png <-- You have failed to put a subfolder prefix in
src/main/resources/images/pea.png
src/main/resources/images
You can either do this, if you have no prefix:
plat.assets().setPathPrefix("")
Or just put your files in the assets sub-folder inside the resources folder.
It's worth noting that the current implementation calls:
getClass().getClassLoader().getResource(...)
Not:
getClass().getResource(...)
The difference is covered elsewhere, but the tldr is that plat.assets.getImage("images/pea.png") will work, but plat.assets.getImage("/images/pea.png") will not.

can I load user packages into eclipse to run at start up and how?

I am new to java and to the eclipse IDE.
I am running Eclipse
Eclipse SDK
Version: 3.7.1
Build id: M20110909-1335
On a windows Vista machine.
I am trying to learn from the book Thinking in Java vol4.
The author uses his own packages to reduce typing. However the author did not use Eclipse and this is where the problem commes in..
This is an example of the code in the book.
import java.util.*;
import static net.mindview.util.print.*;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world");
print("this does not work");
}
this is the contents of print.Java
//: net/mindview/util/Print.java
// Print methods that can be used without
// qualifiers, using Java SE5 static imports:
package net.mindview.util;
import java.io.*;
public class Print {
// Print with a newline:
public static void print(Object obj) {
System.out.println(obj);
}
// Print a newline by itself:
public static void print() {
System.out.println();
}
// Print with no line break:
public static void printnb(Object obj) {
System.out.print(obj);
}
// The new Java SE5 printf() (from C):
public static PrintStream
printf(String format, Object... args) {
return System.out.printf(format, args);
}
} ///:~
The error I get the most is in the statement.
Import static net.mindview.util.print.*;
On this staement the Eclipse IDE says it cannot resolve net
also on the
print("this does not work");
The Eclipse IDE says that the class print() does not exist for the class HelloWorld.
I have been trying to get these to work, but with only limited success, The autor uses another 32 of these packages through the rest of the book.
I have tried to add the directory to the classpath, but that seems to only work if you are using the JDK compiler. I have tried to add them as libraries and i have tried importing them into a package in a source file in the project. I have tried a few other things but cant remember them all now.
I have been able to make one of the files work, the print.java file I gave the listing for in this message. I did that by creating a new source folder then making a new package in that foldeer then importing the print.java file into the package.
But the next time I try the same thing it does not work for me.
What I need is a way to have eclipse load all these .java files at start up so when I need them for the exercises in the book they will be there and work for me, or just an easy way to make them work everytime.
I know I am not the only one that has had this problem I have seen other questions about it on google searches and they were also asking about the Thinking In Java book.
I have searched this site and others and am just not having any luck.
Any help with this or sugestions are welcome and very appreciated.
thank you
Ok I have tried to get this working as you said, I have started a new project and I removed the static from the import statement, I then created a new source folder, then I created a new package in the source folder. Then I imported the file system and selected the the net.mindview.util folder.
Now the immport statement no longer gives me an error. But the the print statement does, the only way to make the print statement work is to use its fully qualified name. Here is the code.
import net.mindview.util.*;
public class Hello2 {
public static void main(String[] args) {
Hello2 test = new Hello2();
System.out.println();
print("this dooes not work");
net.mindview.util.Print.print("this stinks");
}
}
The Error on the print statement is:
The method print(String) is undefined for the type Hello2
and if I try to run it the error I get is:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method print(String) is undefined for the type Hello2
at Hello2.main(Hello2.java:6)
The Statement::::: net.mindview.util.Print.print("this stinks") is the fully qualified print statement and it does not throw an error but it does totally defeat the purpose of the print.java file..
If you have any questions please ask Ill get back to you as soon as I can.
I've had similar issues. I solved it by following the steps below:
Click File->New->Java Project. Fill in UtilBuild for the ProjectName. Chose the option "Use project folder as root and click 'Finish'.
Right-click on UtilBuild in the PackageExplorer window and click New->package. For the Package Name, fill in net.mindview.util
Navigate within the unzipped Thinking In Java (TIJ) folder to TIJ->net\mindview\util. Here you will find all the source code (.java) files for util.
Select all the files in the net\mindview\util folder and drag them to the net.mindview.util package under UtilBuild in Eclipse. Chose the 'Copy Files' option and hit 'OK'.
You will probably already have the 'Build Automatically' option checked. If not, go to Project and click 'Build Automatically'. This will create the .class files from the .java source files.
In Eclipse, right-click on the project you were working on (the one where you couldn't get that blasted print() method to work!) Click Properties and Java Build Path->Libraries. Click 'Add Class Folder...' check the box for UtilBuild (the default location for the .class files).
I think the confusion here arises due to CLASSPATH. If you use Eclipse to build and run your code then Eclipse manages your CLASSPATH. (You don't have to manually edit CLASSPATH in the 'Environment Variables' part of your computer properties, and doing so changes nothing as far as Eclipse Build and Run are concerned.)
In order to call code that exists outside your current project (I will name this 'outside code' for convenience) you need to satisfy three things:
A. You need to have the .class files for that code (as .class files or inside a JAR)
B. You need to indicate in your source code where to look for the 'outside code'
C. You need to indicate where to start looking for the 'outside code'
In order to satisfy these requirements, in this example we:
A. Build the project UtilBuild which creates the .class files we need.
B. Add the statement import static net.mindview.util.Print.*; in our code
C. Add the Class Folder library in Eclipse (Java Build Path->Libraries).
You can investigate the effect of Step C by examining the .classpath file that lives directly in your project folder. If you open it in notepad you will see a line similar to the following:
<classpathentry kind="lib" path="/UtilBuild>
You should combine this with your import statement to understand where the compiler will look for the .class file. Combining path="/UtilBuild" and import static net.mindview.util.Print.*; tells us that the compiler will look for the class file in:
UtilBuild/net/mindview/util
and that it will take every class that we built from the Print.java file (Print.*).
NOTE:
There is no problem with the keyword static in the statement
import static net.mindview.util.Print.*;
static here just means that you don't have to give specify the class name from Print.java, just the methods that you want to call. If we omit the keyword static from the import statement, then we would need to qualify that print() method with the class it belongs to:
import net.mindview.util.Print.*;
//...
Print.print("Hello");
which is slightly more verbose than what is achieved with the static import.
OPINION:
I think most people new to Java will use Eclipse at least initially. The Thinking in Java book seems to assume you will do things via command line (hence it's guidance to edit environment variables in order to update CLASSPATH). This combined with using the util folder code from very early in the book I think is a source of confusion to new learners of the language. I would love to see all the source code organised into an Eclipse project and available for download. Short of that, it would be a nice touch to include the .class files in just the 'net/mindview/util' folder so that things would be a little easier.
U should import package static net.mindview.util not static net.mindview.util.Print
and you should extend the class Print to use its method.......
You should remove the static keyword from your import decleration, this: import static net.mindview.util.print.*; becomes this: import net.mindview.util.print.*;
If that also does not work, I am assuming you did the following:
Create your own project;
Start copying code directly from the book.
The problem seems to be that this: package net.mindview.util; must match your folder structure in your src folder. So, if your src folder you create a new package and name it net.mindview.util and in it you place your Print class, you should be able to get it working.
For future reference, you should always make sure that your package decleration, which is at the top of your Java class, matches the package in which it resides.
EDIT:
I have seen your edit, and the problem seems to have a simple solution. You declare a static method named print(). In java, static methods are accessed through the use of ClassName.methodName(). This: print("this dooes not work"); will not work because you do not have a method named print which takes a string argument in your Hello2 class. In java, when you write something of the sort methodName(arg1...), the JVM will look for methods with that signature (method name + parameters) in the class in which you are making the call and any other classes that your calling class might extend.
However, as you correctly noted, this will work net.mindview.util.Print.print("this stinks");. This is because you are accessing the static method in the proper way, meaning ClassName.methodName();.
So in short, to solve your problem, you need to either:
Create a method named print which takes a string argument in your Hello2 class;
Call your print method like so: Print.print("this stinks");
Either of these two solutions should work for you.
In my case I've dowloaded and decompressed the file TIJ4Example-master.zip. in eclipse workspace folder. The three packages : net.mindview.atunit, net.mindview.simple and net.mindview.util are in this point of the project :
and java programs runs with no problems (on the right an example of /TIJ4Example/src/exercises/E07_CoinFlipping.java)

Categories