Resource loading using ClassLoader - java

I have a resource file I need to load at runtime...it is in src/main/resources
I have successfully loaded the file to an inputStream using :
LoadSAC.class.getClassLoader().getResourceAsStream("someFile.txt");
LoadSAC is the class name ...
However, PMD complains about this suggests I use
Thread.currentThread().getContextClassLoader().getResource(...)
I have tried numerous combinations and can never get the file to be located... Any thoughts... I have trolled a number of searches with plenty of suggestions but none seem to work...
Any thoughts ?

If someFile.txt is in the same folder than LoadSAC.java, you can do:
InputStream is = LoadSAC.class.getResourceAsStream("someFile.txt");
If someFile.txt is in a subfolder subdir, you can do:
InputStream is = LoadSAC.class.getResourceAsStream("subdir/someFile.txt");
If your method in LoadSAC.java is non-static, you can replace LoadSAC.class.getResourceAsStream... by getClass().getResourceAsStream...
Be careful when compiling with ant or maven, by default, only .java file are copied as .class files in the build directory.
You have to write some rules to include someFile.txt in the final jar.
In your resource directory, you can add a little helper class like this:
import java.io.InputStream;
import java.net.URL;
import javax.activation.DataSource;
import javax.activation.URLDataSource;
public abstract class ResourceHelper {
public static URL getURL(String name) {
return ResourceHelper.class.getResource(name);
}
public static InputStream getInputStream(String name) {
return ResourceHelper.class.getResourceAsStream(name);
}
public static DataSource getDataSource(String name) {
return new URLDataSource(getURL(name));
}
}
In LoadSAC.java just call:
InputStream is = ResourceHelper.getInputStream("someFile.txt");

Related

How to read the file entry with same name in multiple library jars with spring boot?

I have a spring application with multiple dependent libraries that have the inner properties/xml that I want to read.
test-app.jar
dep1.jar
dep2.jar
dep3.jar
...
Each of the dep1/2/3 jars have the file called META-INF/config.properties which contains the files to further read within that dependent jars.
I tried the ResourceUtils.getURL("classpath:/META-INF/config.properties"), but it always reads from the first dependent file.
How can I read from each jars that contains the same name?
I found this solution after searching:
final Enumeration<URL> resEnum =
MyClass.class.getClassLoader()
.getResources("META-INF/config.properties");
final List<URL> resources =
Collections.list(resEnum);
//Copied from riptutorial.com
Refs:
https://riptutorial.com/java/example/19290/loading-same-name-resource-from-multiple-jars
https://stackoverflow.com/a/6730897
Updated solution:
package abc;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
public class MultipleClasspathEntries {
public static void main(String[] args) throws IOException {
final Enumeration<URL> resEnum =
MultipleClasspathEntries.class.getClassLoader()
.getResources("META-INF/MANIFEST.MF");
while (resEnum.hasMoreElements()) {
System.out.println(resEnum.nextElement());
}
}
}
//Copied from riptutorial.com
$JAVA_HOME/bin/javac abc/*.java
$JAVA_HOME/bin/java -cp /c/so-67847004/commons-lang-2.4.jar:/c/so-67847004/commons-collections-3.2.1.jar:. abc.MultipleClasspathEntries
Output:
jar:file:/C:/so-67847004/commons-lang-2.4.jar!/META-INF/MANIFEST.MF
jar:file:/C:/so-67847004/commons-collections-3.2.1.jar!/META-INF/MANIFEST.MF

Import class in Java via absolute path

I've been trying to import a .class via absolute path while code is running and I don't know how to do it.
I found a way to import a class when it's already in project's build path by Class.forName();but I need to find a way to load a class that is not in build path.
The goal is:
User is able to upload his own .class file which is then saved locally to a specific folder and path is saved in database
Via GUI user can select this file to be used while code is running
My code should load a class via this given absolute path while code is running
The problem is with 3rd point because I don't know if it is possible to load a class while code is running.
I've tried using URLClassLoader but I'm getting ClassNotFound error.
EDIT:
Basically, I have this static function which should return Class by it's name, but urlClassLoader.loadClass() throws error.
Name of a file is J48.class so for className argument I've tried using "J48", "J48.class" but none work.
Additionaly I've tried setting folder classifiers to build path and setting argument to "weka.classifiers.trees.J48" which is full path with package to this class (package structure is weka.classifiers.trees).
`public static Class getClassByName(String className) throws MalformedURLException, ClassNotFoundException
{
URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[] {
new URL("file:///D:\\xampp\\htdocs\\prog-ing\\classifiers\\")
});
Class class = urlClassLoader.loadClass(className);
return class;
}`
I think I have a suggestion to solve your problem...
I know two options:
Option 1: Read a class file from directory.
Example:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Test5 extends ClassLoader {
private static final String PATH = "C://myFiles//";
public static void main(String[] args) {
Class clazz = getClassFromName("Test4");
System.out.println(clazz);
}
private static Class getClassFromName(String className) {
File file = new File(PATH + className + ".class");
try {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
return defineClass(className, bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
This will print something like this:
class Test4
- Option 2: Read a class file from JAR.
Example:
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class Test5 {
private static final String PATH = "C://myFiles//";
public static void main(String[] args) {
Class clazz = getClassFromFile("myJar.jar", "com.mypackage.Test4");
System.out.println(clazz);
}
private static Class getClassFromFile(String fromFile, String className) {
try {
URL url = new URL("file:////" + PATH + fromFile);
URLClassLoader urlClassLoader = URLClassLoader.newInstance(
new URL[] {
url
});
return urlClassLoader.loadClass(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
}
This will print something like this:
class com.mypackage.Test4
Note that to read a jar file I had to put the full path of package to the class file.
I hope I've helped.
Okay so after thinking a bit, I only got to the one solution (still not satisfied with it) which is following:
every class that needs to be uploaded by user is saved into workspace of this project and therefore I am able to get class using Class.forName(); pointing out this "folder" of uploaded classes, in my case: Class.forName("classifiers.className");

Eclipse not finding file?

I am using eclipse and I have my text file in the correct directory (src folder). I just want to read the file and count all the words in it. For some reason I am getting a file not found exception being thrown.
here is my code.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Tester {
public static int getSizeOfDictionary(File dictionary)
throws FileNotFoundException {
int count = 0;
Scanner reader = new Scanner(dictionary);
while (reader.hasNextLine()) {
reader.nextLine();
count++;
}
reader.close();
return count;
}
public static void main(String[] args) throws FileNotFoundException {
File test = new File("words.txt");
System.out.println(getSizeOfDictionary(test));
}
}
You could use this.getClass().getResource("words.txt") which will find that file on the current classpath.
From the main method you could use: Tester.class.getResource("words.txt")
when eclipse launches jvm it sets current directory to project base directory generally (unless you modify the default current directory)
${workspace_loc}/project_name
so you need to change your File initialization to
File test = new File("src/words.txt");
Note:
It will just be limited to this project structure, if you export it to jar it will not work any more, I assume you just need it as part of exercise
You have to use property class to access your file within class-path and source folder
you can try like:
this.getClass().getResourceAsFile("words.txt")

How to run a jar file from a separate jar file? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Execute another jar in a java program
Basically I want to run an external .jar from the one I'm working on now.
I.e. I want to run foo.jar from bar.jar
I've tried using Runtime and Process to execute "java -jar foo.jar", but it opens foo.jar and then it closes immediately. Any tips?
The easiest solution (as Thorn pointed out) would be to have the jar as a build-time dependency and invoke it statically from your code:
ExternalJarMainClass.main(new String[]{"arguments", "to", "main"});
But if that is not possible, you can use a URLClassLoader to load the jar dynamically. If the jar is indeed runnable, then you can read the main class from META-INF/MANIFEST.MF and invoke main via reflection.
This is a different approach from creating a separate process, as the external code will run in the same process as your application. Perhaps this is desirable, perhaps not - that depends on the situation.
Below's a (hastily written and flawed) sample helper class that does just that.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JarRunner {
private final Method entryPoint;
public JarRunner(File jarFile) throws
ClassNotFoundException,
IOException,
NoSuchMethodException {
URL jarUrl = jarFile.toURI().toURL();
URLClassLoader loader = URLClassLoader.newInstance(
new URL[]{jarUrl});
URL manifestUrl = loader.findResource("META-INF/MANIFEST.MF");
String manifest = resourceToString(manifestUrl);
Class<?> clazz = loader.loadClass(findMainClassName(manifest));
entryPoint = clazz.getMethod("main", String[].class);
}
public void run(String[] argsToMain) throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException {
entryPoint.invoke(null, (Object) argsToMain);
}
private static String resourceToString(URL url) throws IOException {
InputStream contentStream = url.openStream();
try {
BufferedReader r = new BufferedReader(
new InputStreamReader(contentStream));
StringBuilder sb = new StringBuilder();
String line = null;
do {
line = r.readLine();
if (line != null) {
sb.append(line).append('\n');
}
} while (line != null);
return sb.toString();
} finally {
contentStream.close();
}
}
private static String findMainClassName(String manifest) {
Matcher m = MAIN_CLASS_PATTERN.matcher(manifest);
if (m.find()) {
return m.group(1);
}
return null;
}
private static final Pattern MAIN_CLASS_PATTERN =
Pattern.compile("Main-Class: (.+)");
}
Sample usage:
JarRunner jr = new JarRunner(new File("path/to/MyJar.jar"));
jr.run(new String[]{"arg1", "arg2"});
Can you run foo.jar directly? Does it have a manifest with a main method?
I am guessing that you can. So you want to launch the main method inside of a class like foo.Main
Option 1: Include foo.jar in the classpath. If you are using an IDE, then this just means adding foo.jar as a library. Now you are free to import the package (lets call the package foo) and launch your second java program from a single line of Java code:
foo.Main.main(null);
Most likely you would want to do this in a separate thread:
class FooRunner extends Thread {
public void run() {
foo.Main.main(null);
}
}
and then you would launch with this:
FooRunner secondaryApp = new FooRunner();
secondaryApp.start();
Option 2
You can load the classes in the Foo package at runtime using a class loader.
See the Javadocs for java.lang.ClassLoader and this example of a CustomClassLoader
Check java -jar foo.jar runs correctly from command line. Also ensure java is there in the path. It may be better to provide absolute path to java.exe in the arguments.
Please consider using ProcessBuilder instead of Runtime.

How do I correctly load resources from a network directory in the java classpath?

Our java application relies on some resources which are available on a network share. This network share is located on the classpath, and the resources are read at runtime using MyClass.class.getResourceAsStream("/myfile.jpg").
java -Djava.class.path=\\myserver\myshare:C:\myjar.jar MainClass
When the share is available at startup, everything runs smoothly. Image and properties files which are located in the share can be read using getResourceAsStream(). However, if the share is not online when the application starts, even if the share comes online before any resources are read, they cannot be read using getResourceAsStream().
Doing some digging using eclispse + decompiler, I noticed one difference. The default classloader inherits from URLClassLoader, and its ucp member (URLClassPath) contains a list of URLClassPath.Loader instances. In the first scenario, it contains a URLClassPath.FileLoader and a URLClassPath.JarLoader. In the second scenario, it only contains a jar loader.
It's like java determines that the classpath entry is invalid and completely discards it.
Why is this? How can I avoid it?
Update
I am unable to change the mechanism by which we are loading resources because of a few reasons:
There are far too many areas which currently load files this way for me change at the moment
There are situations where by the resource is actually being loaded by a third party component
I have no problem creating a custom class loader, I just need some guidance on how to do it.
I tried with this, but was unable to get expected results:
import java.net.URL;
import java.net.URLClassLoader;
public class MyUrlClassLoader extends URLClassLoader {
public MyUrlClassLoader(ClassLoader parent) {
super(new URL[0], parent);
System.out.println("MyUrlClassLoader ctor");
}
#Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println("url find class " + name);
return super.findClass(name);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("url load class " + name);
return super.loadClass(name);
}
#Override
public URL getResource(String name) {
System.out.println("url get resource " + name);
return super.getResource(name);
}
}
import java.net.URL;
public class ClassLoaderMain {
public static void main(String[] args) throws ClassNotFoundException {
URL url = ClassLoaderMain.class.getResource("/myfile.txt");
System.out.print("Loaded? ");
System.out.println(url != null);
System.out.println(ClassLoaderMain.class.getClassLoader().toString());
System.out.println(MyUrlClassLoader.class.getClassLoader().toString());
System.out.println(FakeClass.class.getClassLoader().toString());
}
}
When I run java -cp . -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain
This outputs:
MyUrlClassLoader ctor
url load class java.lang.System
url load class java.nio.charset.Charset
url load class java.lang.String
url load class ClassLoaderMain
Loaded? true
sun.misc.Launcher$AppClassLoader#923e30
sun.misc.Launcher$AppClassLoader#923e30
sun.misc.Launcher$AppClassLoader#923e30
So my class loader is being created, and load class is being called, but it doesn't appear to be the class loader for the classes it is loading?
I ended up resolving this by creating my own ClassLoader, deriving from URLClassLoader.
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class CustomClassLoader extends URLClassLoader {
public CustomClassLoader(ClassLoader parent) {
// System classloader will filter inaccessible URLs.
// Force null parent to avoid using system classloader.
super(createURLReferences(), null);
}
/**
* Build an array of URLs based on the java.class.path property.
* #return An array of urls to search for classes.
*/
private static URL[] createURLReferences() {
String classpath = System.getProperty("java.class.path");
String[] classpathEntries = classpath.split(System.getProperty("path.separator"));
List<URL> urls = new ArrayList<URL>();
for (String classpathEntry : classpathEntries) {
File classpathFile = new File(classpathEntry);
URI uri = classpathFile.toURI();
try {
URL url = uri.toURL();
urls.add(url);
} catch (MalformedURLException e) {
System.out.println("Ignoring classpath entry: " + classpathEntry);
}
}
return urls.toArray(new URL[urls.size()]);
}
}

Categories