Java class.getResource() returns null - java

I am trying to use files in resource directory that was marked as "resource root" in IntelliJ, but the below code fails to find the file.
Could you tell me what was wrong? thanks.
public class ResourceTest {
public void testResource() {
URL url = this.getClass().getResource("resources/table.1gram");
System.out.println(url);
}
public static void main(String[] args) {
ResourceTest rt = new ResourceTest();
rt.testResource();
}
}

Files in the resources folder will be packaged to the root of the .jar file, meaning that during development, the resources folder itself is in the classpath, so you need this.getClass().getResource("/table.1gram"), or without the / since your class is in the unnamed package, aka also in the root of the .jar file.

Related

Error: Package doesn't exists when importing a user defined package from a class

Here My first file code
package com.shubham.packages.a;
import static com.shubham.packages.b.Message.Hello;
public class Greeting {
public static void main(String[] args) {
System.out.println("Hello World");
Hello();
}
}
Here my second file code
package com.shubham.packages.b;
public class Message {
public static void main(String[] args) {
}
public static void Hello() {
System.out.println("This is Awesome.");
}
}
Here the error I got when I run the program.
When you compile your code javac needs to know where to look for all of your source/class files. You could go to "java_tutorial" folder and run.
javac com/shubham/packages/a/Greeting.java com/shubham/packages/b/Message.java
That should compile both of your java files into class files at the same location. Then you should be able to run.
java com.shubham.packages.a.Greeting
I might be using the wrong slashes for windows
You can explicitly name all of the necessary java files, so this should cause both Greeting.java and Message.java to be compiled in place.
When you run java, the CWD is on the classpath by default so that means the package com.shubham.packages.a and ...b should be on the classpath in their correct location.
A slightly better way to do this is to create a folder called "build" or whatever you like.
javac -d build com/shubham/packages/a/Greeting.java com/shubham/packages/b/Message.java
That will output the class files to the build folder. Then when you run it.
java -cp build com.shubham.packages.a.Greeting

get the execution location from within a library jar

I have a class named Utils with a static method that should determine the execution location.
public class Utils {
public static Path getExecutionLocation() throws URISyntaxException {
return Paths.get(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
Within eclipse this gives me: C:\Users\USERNAME\workspace\PROJECT\bin\main\
Run as a jar this gives me: C:\PATH\TO\JAR\thatJar.jar
Both is correct and expected.
Now I have that Utils class inside a library called someLib.jar.
When I use that library in another project it works if I build a jar of that project with someLib.jar inside.
But in eclipse it returns the path to someLib.jar.
I want it to return the path to the execution directory of the project:
C:\Users\USERNAME\workspace\A_PROJECT_USING_SOMELIB\bin\main\
I tried
return new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).toPath();
But that failed inside a jar because getResource(".") results in null.
I could give getExecutionLocation a class from inside the project as a parameter and excute getProtectionDomain() on that. But I want to ask here if someone knows a better solution.
Try this:
public class Utils {
public static Path getExecutionLocation(Class c) throws URISyntaxException {
return Paths.get(c.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
So you pass the class as an argument to the function. For example:
public class Main
{
public static void main(String[] args)
{
Utils.getExecutionLocation(Main.class);
}
}
Note that there may be more straightforward solutions,
But this is the first one that came into my mind, and I thought, why not :)
I've found a solution based on ClassLoader.getSystemClassLoader() approach that gives me the class loader responsible for the main entry point of the project that is using someLib.jar.
Within an IDE I can use getResource(".") to get URL of the root path of all resources (and sources).
From jar file this does not work. So I use getResource("META-INF") to get URL of the META-INF folder (that has the manifest inside) and should always exist in jar files.
Maybe still not optimal. But so far I can work with it.
public static Path getExecutionLocation() throws URISyntaxException, IOException {
// System ClassLoader is on the highest level and responsible for the main entry point
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// get the resources root path (works within IDEs)
URL executionLocation = systemClassLoader.getResource(".");
// fallback for jars
if(executionLocation == null) {
// look for META-INF folder
URL metaInfLocation = systemClassLoader.getResource("META-INF");
// URL looks like "jar:file:/C:/path/to/jar/jarfile.jar!/META-INF"
// openConnection on URL - does not really establish connection but checks if URL would be valid
JarURLConnection connection = (JarURLConnection) metaInfLocation.openConnection();
// extracts URL to jar file
executionLocation = connection.getJarFileURL();
}
// impossible to determine
if(executionLocation == null) throw new RuntimeException("Impossible to determine exeution location");
return Paths.get(executionLocation.toURI());
}

Unable to access directory classes after setting classpath

I'm having a hard time setting the classpath for a directory to a package of classes. I'm trying to run a jar file that takes a directory as a command line argument. The program uses the directory to access class files in a folder and uses reflection to explore the class fields and methods.
final File folder = new File(args[0]);
classList = dirParse.listFilesForFolder(folder);
I then go through the classList, get the name of each class, and use the Class.forName() method to access the classes.
Class c = Class.forName(className);
For the line above to work, I have to set the classpath to the address of the directory containing the classes.
I can get the program to run just fine when I'm using a directory of classes that do not belong to a package like below:
java -cp "Explorer.jar:/Users/john/Desktop/TestClass/" explorer.ExplorerDemo /Users/john/Desktop/TestClass/
However, for the following line, monopoly is a package and the program throws a ClassNotFoundException after calling Class.forName(className)
java -cp "Explorer.jar:/Users/john/Desktop/Programming\ Project/Monopoly/build/classes/monopoly/" explorer.ExplorerDemo /Users/john/Desktop/Programming\ Project/Monopoly/build/classes/monopoly/
For testing purposes, I tried adjusting `Class.forName() call to include the package name like below:
Class c = Class.forName("monopoly."+className);
However, this also throws ClassNotFoundException.
Class.forName is a shortcut to obtaining class information within the context of ClassLoader of the current class. Javadoc states that this is equivalent to
Class.forName("Foo", true, this.getClass().getClassLoader())
Provided that you class directory is supplied as runtime parameter and is not part of the original classpath, I would suggest you instantiating custom URLClassLoader instance that will be pointing to your directory.
Sample code:
public class ReflectionClassAnalysis {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
// URLClassLoader supports both directories and jar files
Path directory = Paths.get("/some/directory/");
Path jar = Paths.get("/some/binary.jar");
// You may be interested in providing parent ClassLoader for your new instance
// You can either use current class ClassLoader like
ClassLoader contextClassLoader = ReflectionClassAnalysis.class.getClassLoader();
// or current thread ClassLoader
// ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
URLClassLoader myClassLoader = new URLClassLoader(
new URL[]{
directory.toUri().toURL(),
jar.toUri().toURL()
},
contextClassLoader
);
// You may use ClassLoader directly to load class meta
Class<?> externalClass = myClassLoader.loadClass("your.class.name");
// or supply ClassLoader to forName method
// Class.forName("your.class.name", true, myClassLoader);
// Do your class analysis here
}
}
For JAR with classpath instructions please refer to: Run a JAR file from the command line and specify classpath

Change the system class loader at runtime

Main class
public class Main {
public static void main(String[] args) {
// Class load
A a = new A();
a.msg();
}
}
A class
public class A {
public void msg() {
System.out.println("msg");
}
}
I have written code in the main class that calls a msg() method of class A
After I created the jar file, I pull out A.class.
Then the path will have a jar file with missing A.class, and A.class.
A a = new A();
a.msg();
How do I dynamically load and run A.class without making any changes to the above code?
Please help me..
Looks like you want to load a class dynamically. I would recommend you to create a jar and load it using URIClassLoader. There is a really good answer here:- How should I load Jars dynamically at runtime?
A.class has to be in the classpath somewhere for the code to run. you can put it in a jar of its own, and add the second jar to the classpath. Then the class loader can find it.

where to put .properties files in an Eclipse project?

I have a very simple properties file test I am trying to get working: (the following is TestProperties.java)
package com.example.test;
import java.util.ResourceBundle;
public class TestProperties {
public static void main(String[] args) {
ResourceBundle myResources =
ResourceBundle.getBundle("TestProperties");
for (String s : myResources.keySet())
{
System.out.println(s);
}
}
}
and TestProperties.properties in the same directory:
something=this is something
something.else=this is something else
which I have also saved as TestProperties_en_US.properties
When I run TestProperties.java from Eclipse, it can't find the properties file:
java.util.MissingResourceException:
Can't find bundle for base name TestProperties, locale en_US
Am I doing something wrong?
Put it at the root level of one of your source paths, or fully qualify the resource name in the call to getBundle, e.g.
ResourceBundle myResources =
ResourceBundle.getBundle("com.example.test.TestProperties");
See the docs for ResourceBundle.getBundle(String, Locale, ClassLoader) for more information.
Do NOT put your propierties files into your src folder! Obviously that works, but basically this is NOT how you should approach your problems. Create a new folder in your project, for instance a 'Resources' folder, add it to the classpath in project properties and put all files other than .java there.
I have just been trying to solve this problem as well, I have found that you must refresh Eclipse's list of files before you try to run your project. Then you can have your files in the base directory and use them as normal.
put the TestProperties_en_US.properties(propery) file in the src folder and then run the program it will run
Aha, thanks a bunch. This also works.
package com.example.test;
import java.util.ResourceBundle;
public class TestProperties {
public static void main(String[] args) {
ResourceBundle myResources =
ResourceBundle.getBundle(TestProperties.class.getCanonicalName());
for (String s : myResources.keySet())
{
System.out.println(s);
}
}
}

Categories