Java getResource return null mac - java

I am very new to StackOverflow and I've done my best to fix this problem before posting this question here. I'm faced with the problem of getResource() returning null. I have a hunch that this is because I'm on a mac and the pathing is different here than on a PC (where this code seems to work fine). This is the code:
public class SampleClass
{
static String imgpath = "/theimage.png";
public static void main(String[] args)
{
System.out.println(imgpath);
System.out.println(SampleClass.class.getResource(imgpath));
try
{
BufferedImage image = ImageIO.read(SampleClass.class.getResource(imgpath));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
src, res and bin are all in the same directory and theimage.png is inside of res.
System.out.println(SampleClass.class.getResource("imgpath")); gives me null.

I had the same issue on my mac using spring boot :
the file is located on properties/report/example.jasper
when the path was : "report/example.jasper" i got nullPointerException
So i changed to : "./report/example.jasper" and It works fine without any bug.
InputStream inStream = null;
try {
inStream = ExportController.class.getClassLoader().getResourceAsStream(path);
final JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inStream);
jasperReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
} catch (final JRException jre) {
throw new TechnicalException("Error when export jasper");
} finally {
if (inStream != null) {
inStream.close();
}
}

you get nullpointer exception because there is no image named imgpath in that folder
public class SampleClass
{
static String imgpath = "/theimage.png";
public static void main(String[] args)
{
System.out.println(imgpath);
System.out.println(SampleClass.class.getResource(imgpath));
try
{
BufferedImage image = ImageIO.read(SampleClass.class.getResource(imgpath));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

I faced the same issue on Mac. Here how I now get files from resources. For example, I have a common Maven project with resource folder in src/main. In resource folder I have a file "test.txt".
To get a path to the file:
public class Utils {
public static String getFilePathInResources() {
URL url = Utils.class.getClassLoader().getResource("test.txt");
return url.getPath();
}
}
Here the filename is hardcored just for clearity, of course, really it is a parameter in the method.
If set a filename as "/test.txt" with "/" - this will give null.
URL url = Utils.class.getClassLoader().getResource("/test.txt"); // url == null

Related

How to load ResourceBundles within loaded JAR

I have a problem with loading resource bundles in loaded jars. The main program is loading jars from a folder with a plugin manager. When an object of the main class of a jar is initialized by the plugin manager, resource bundles of this jar can be loaded. By this, I mean in a static block or in a constructor. Otherwise, an MissingResourceException is thrown. Like when you call a method on that object, that tries to load an existing resource-bundle
Currently, I use a static block at the beginning of the main class of a jar to load all resource bundles of the plugin with possible locales. Because of this, the resource bundles will be cached for some time. Also, my current way seems to work out for sub-loaded jars the same way as for the loaded jar
public class PluginMain implements PluginInterface {
static {
for (Locale availableLocale : getAvailableLocales()) {
try {
ResourceBundle resourceBundle = ResourceBundle.getBundle(BUNDLE_PATH, availableLocale);
} catch (MissingResourceException e) {
e.printStackTrace();
}
}
}
...
}
I think it's about the classLoader that is loading the resource-bundle. Still i cannot find a good solution.
I already tried to find some solutions. The best i could find fitting is Loading with ResourceBundle from inside a jar, but that did not work out.
Edit: I load my jars like this
public class PluginManagerImpl implements PluginManager {
private final List<PluginInterface> loadedPlugins = new ArrayList<>();
private final String path;
public PluginManagerImpl(String path) {
File pluginsDir = new File(path, "plugins");
this.path = pluginsDir.getPath();
if (pluginsDir.exists()) {
//pluginsfolder exists
File[] files = pluginsDir.listFiles();
if (files != null) {
for (File f : files)
if (!f.isDirectory()) {
loadPlugin(f);
}
}
} else {
//pluginsfolder does not exist
if (pluginsDir.mkdir()) {
Output.WriteLine("Dictionary created: " + pluginsDir.getPath());
}
}
}
#Override
public void loadPlugin(File file) {
URL urlFile;
//trying to load file, convert it first to URI and then to URL
try {
urlFile = file.toURI().toURL();
} catch (MalformedURLException e) {
Output.WriteLineProblem(e.getMessage(), 4);
return;
}
//trying to create JAR-file from file
try (
//use JarFIle and URLClassLoader as auto-closable
JarFile jarFile = new JarFile(file);
//use classloader of this class as parent classLoader
URLClassLoader classLoader = new URLClassLoader(new URL[]{urlFile}, this.getClass().getClassLoader())
) {
//load manifest
Manifest manifest = jarFile.getManifest();
//read attributes from manifest
Attributes attributes = manifest.getMainAttributes();
//get main class from attributes
String main = attributes.getValue(Attributes.Name.MAIN_CLASS);
if (main == null) {
Output.WriteLineProblem(file.getName() + " has no main specified");
return;
}
String title = attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
if (title == null) {
//https://maven.apache.org/shared/maven-archiver/index.html
Output.WriteLineProblem(file.getName() + " has no implementation title specified");
return;
}
//https://javapapers.com/core-java/java-class-loader/
//load class with classLoader of jarFile
Class<?> cl = classLoader.loadClass(main);
//get implemented interfaces of class
Class<?>[] interfaces = cl.getInterfaces();
//iterate over interfaces and check for PluginInterface.class
boolean isPlugin = false;
for (Class<?> anInterface : interfaces) {
if (anInterface.equals(PluginInterface.class)) {
isPlugin = true;
break;
}
}
if (isPlugin) {
//load all classes in jar file
loadClassesOfjarFile(jarFile, cl.getClassLoader());
//add the pluginfile
PluginInterface plugin = (PluginInterface) cl.getConstructor().newInstance();
plugin.calledAfterInstancing(new File(path, title).getPath());
Output.WriteLine("Loaded Plugin " + title);
loadedPlugins.add(plugin);
}
} catch (Exception e) {
Output.WriteLineProblem("Error on checking " + file.getName() + " for plugin");
e.printStackTrace();
}
}
public static void loadClassesOfjarFile(JarFile jarFile, ClassLoader classLoader) {
jarFile.entries().asIterator().forEachRemaining(jarEntry -> {
String jarEntryName = jarEntry.getName();
if ((jarEntryName.endsWith(".class"))) {
String className = jarEntry.getName().replaceAll("/", "\\.");
String myClass = className.substring(0, className.lastIndexOf('.'));
try {
Class<?> clazz = classLoader.loadClass(myClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else if (jarEntryName.endsWith(".xml")) {
String resourceName = jarEntry.getName().replaceAll("/", "\\.");
classLoader.getResourceAsStream(jarEntry.getName());
}
});
}
}
Edit 2: Here a sample project to test
The resource bundles are contained in the the resource folder of the plugin.
Hierarchy of the project
Sample for the main program:
package main;
public class Main {
public static final String DEFAULT_PATH = FileSystems.getDefault().getPath("").toAbsolutePath().toString();
public static void main(String[] args) {
PluginManager plugins = new PluginManager(DEFAULT_PATH);
List<PluginInterface> loadedPlugins = plugins.getLoadedplugins();
for (PluginInterface loadedPlugin : loadedPlugins) {
loadedPlugin.loadResourceBundle(Locale.ENGLISH);
}
}
}
Sample for plugin:
package plugin;
public class Main implements PluginInterface {
static {
Locale locale = Locale.ENGLISH;
ResourceBundle main = ResourceBundle.getBundle("mainLoadedInStatic", locale);
//only uncomment to check, that it would work if loaded in static
// ResourceBundle mainNotLoadedInStatic = ResourceBundle.getBundle("mainNotLoadedInStatic", locale);
}
#Override
public void loadResourceBundle(Locale locale) {
ResourceBundle mainLoadedInStatic = ResourceBundle.getBundle("mainLoadedInStatic", locale);
ResourceBundle mainNotLoadedInStatic = ResourceBundle.getBundle("mainNotLoadedInStatic", locale);
}
}
The error should be:
Exception in thread "main" java.util.MissingResourceException: Can't find bundle for base name mainNotLoadedInStatic, locale en
at java.base/java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2045)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1683)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1586)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1549)
at java.base/java.util.ResourceBundle.getBundle(ResourceBundle.java:932)
at plugin.Main.loadResourceBundle(Main.java:19)
at main.Main.main(Main.java:18)
I discovered that closing the URLClassLoader (as autocloseable) in loadPlugin of PluginManagerImpl was causing the Problem.
The Resources are tried to be loaded with that URLClassLoader and if it is closed, it will fail.
Which effect would occur, if the URLClassLoader doesn't get closed at all? As far as i understand this could have a negativ effect because of an unclosed JarFile.

Trying to laod dependencys in java runtime

I just want to load .jar libraries in my running programm. Therefore i created a "libs" folder in my programm directory.
In the main in call the function loadDependencies() to load all the .jar files in the libs directory to use them in a plugin extension system.
Now the problem, it does not work :)
Here the code i tried so far:
public class DependencyLoader {
private static final Class<?>[] parameters = new Class[]{URL.class};
public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}
public static void addFile(File f) throws IOException {
addURL(f.toURI().toURL());
}
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Class<?> sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL",parameters);
method.setAccessible(true);
method.invoke(sysloader,new Object[]{ u });
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}
}
public static void loadDependencies(){
File libsDir = new File("/home/admin/network/lobby/libs");
if(!libsDir.exists() && !libsDir.mkdirs() && !libsDir.isDirectory()){
System.out.println("could not find lib directory!");
System.exit(-1);
}
for(File file : libsDir.listFiles()){
if(file.getName().endsWith(".jar")){
System.out.println("loading dependency "+file.getName());
try {
addFile(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The libraries are found . But not loaded correctly. The result is a noclassdef error.
Hope someone can help me.
Regards!

Java file copy fails

I have written a very simple Java program to copy a file passed as an argument to the /tmp directory. The program produces several Java exceptions.
public class CopyFile {
public static void main(String[] args) throws IOException {
String fqp2File = "";
if (new File(args[0]).isFile()) {
fqp2File = args[0];
}
else {
System.out.println("Passed argument is not a file");
}
copy(fqp2File, "/tmp");
}
private static boolean copy(String from, String to) throws IOException{
Path src = Paths.get(from);
Path dest = Paths.get(to);
try {
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
return true;
} catch (IOException ioe) {
System.err.format("I/O Error when copying file");
ioe.printStackTrace();
return false;
}
}
}
When I run this program I get these errors:
java -jar CopyFile.jar /home/downloads/dfA485MVSZ.ncr.pwgsc.gc.ca.1531160874.13500750
I/O Error when copying filejava.nio.file.FileSystemException: /tmp:
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:103)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:114)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:119)
at sun.nio.fs.UnixCopyFile.copy(UnixCopyFile.java:578)
at sun.nio.fs.UnixFileSystemProvider.copy(UnixFileSystemProvider.java:265)
at java.nio.file.Files.copy(Files.java:1285)
at ca.gc.ssc.gems.esnap.cipo.CopyFile.copy(CopyFile.java:39)
at ca.gc.ssc.gems.esnap.cipo.CopyFile.main(CopyFile.java:31)
To test your code I used C:/tmp/test.txt; as your args[0]. I fixed the issue by giving the output a filename to write to shown below:
Path dest = Paths.get(to);
to
Path dest = Paths.get(to, "test2.txt");
And it now successfully copied the file into that name, you can modify the filename however you want or add logic to change filename automatically.

User URLClassLoader to load jar file "on the fly"

Ok, basically, I try to use the method described here JarFileLoader to load a jar containing a class that will be used the same as if it was on the classpath (the class name will be dynamic so that we can just add any jar with any class and the program will load it through parsing a text file, in the main line).
Problem is that when I debug and check the URLClassLoader object
protected Class<?> findClass(final String name)
Line :
Resource res = ucp.getResource(path, false);
the getResource() does not find the class name in parameter.
Does someone already try loading a jar file this way ?
Thanks.
Loader :
public class JarFileLoader extends URLClassLoader {
public JarFileLoader() {
super(new URL[] {});
}
public JarFileLoader withFile(String jarFile) {
return withFile(new File(jarFile));
}
public JarFileLoader withFile(File jarFile) {
try {
if (jarFile.exists())
addURL(new URL("file://" + jarFile.getAbsolutePath() + "!/"));
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
return this;
}
public JarFileLoader withLibDir(String path) {
Stream.of(new File(path).listFiles(f -> f.getName().endsWith(".jar"))).forEach(this::withFile);
return this;
}
}
Main :
public static void main(String[] args) {
new Initializer();
JarFileLoader cl = new JarFileLoader();
cl = cl.withFile(new File("libs/dpr-common.jar"));
try {
cl.loadClass("com.*****.atm.dpr.common.util.DPRConfigurationLoader");
System.out.println("Success!");
} catch (ClassNotFoundException e) {
System.out.println("Failed.");
e.printStackTrace();
} finally {
try {
cl.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Here the test class I used. When I debug URLClassLoader I can see in the third loop the path of the jar file(loop on the classpath and the URL you add here), but still does not find ressource (and cannot debug the class URLClassPath so do not know what getRessource does exactly).
Ok I take the answer from this question : How to load all the jars from a directory dynamically?
And changing the URL part at the beginning with the way it is done in the long part it works.
So an example could be :
String path = "libs/dpr-common.jar";
if (new File(path).exists()) {
URL myJarFile = new File(path).toURI().toURL();
URL[] urls = { myJarFile };
URLClassLoader child = new URLClassLoader(urls);
Class DPRConfLoad = Class.forName("com.thales.atm.dpr.common.util.DPRConfigurationLoader", true, child);
Method method = DPRConfLoad.getDeclaredMethod("getInstance");
final Object dprConf = method.invoke(DPRConfLoad);
}
All my time wasted in search while it was the example which was wrong... Still does not understand why they use a stupid URL like "jar:file..." etc.
Thanks everyone.

Issue with loading class from jar file represented as byte array

I'm trying to create an instance of a class from jar file loaded on a byte array.
I'm receiving two args:
1. byte[] which represents jar file with required class
2. Qualified class name
When I'm testing it locally it works as expected, but when I upload exactly the same jar file with the same qualified class name remotely (using web application implemented with Spring MVC for back and AngularJS for front end deployed in Tomcat server) It can't find the required class:
java.lang.ClassNotFoundException
When I was debugging, it turned out, that classloader is properly invoked but no one class is loaded from jar.
I would be grateful if anyone can tell what can be the reason of that difference or how can I implement this functionality in other ways.
A method which loads class and returns an instance of it:
public static <T> T getInstanceOfLoadedClass(byte[] jarFileBytes, String qualifiedClassName) throws ClassFromJarInstantiationException {
LOGGER.info("Getting instance of class from loaded jar file. Class name: " + qualifiedClassName);
try {
return (T) Class.forName(qualifiedClassName, true, new ByteClassLoader(jarFileBytes)).newInstance();
} catch (InstantiationException | IllegalAccessException | IOException | ClassNotFoundException | NoSuchFieldException e) {
LOGGER.error("Exception was thrown while reading jar file for " + qualifiedClassName + "class.", e);
throw new ClassFromJarInstantiationException(e);
}
}
Custom ByteClassLoader:
public class ByteClassLoader extends ClassLoader {
private static final Logger LOGGER = Logger.getLogger(ByteClassLoader.class);
private final byte[] jarBytes;
private final Set<String> names;
public ByteClassLoader(byte[] jarBytes) throws IOException {
this.jarBytes = jarBytes;
this.names = loadNames(jarBytes);
}
private Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return Collections.unmodifiableSet(set);
}
#Override
public InputStream getResourceAsStream(String resourceName) {
if (!names.contains(resourceName)) {
return null;
}
boolean found = false;
ZipInputStream zipInputStream = null;
try {
zipInputStream = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
if (entry.getName().equals(resourceName)) {
found = true;
return zipInputStream;
}
}
} catch (IOException e) {
LOGGER.error("ByteClassLoader threw exception while reading jar byte stream for resource: "+resourceName, e);
e.printStackTrace();
} finally {
if (zipInputStream != null && !found) {
try {
zipInputStream.close();
} catch (IOException e) {
LOGGER.error("ByteClassLoader threw exception while closing jar byte stream for resource: "+resourceName, e);
e.printStackTrace();
}
}
}
return null;
} }
The problem was that the class required to be loaded was in a range of classloader while it was tested.
Hope it helps someone in solving this problem because it is really easy to miss.

Categories