Trying to laod dependencys in java runtime - java

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!

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.

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.

java delete directory in windows

I try to delete a directory using java,here is my code
public static void delDirectory(String path) throws IOException {
Path p = Paths.get(path);
delHelp(p);
}
private static void delHelp(Path p) throws IOException {
if (!p.toFile().exists()) {
return;
} else if(p.toFile().isFile()){
log.debug("delete file:" + p.toAbsolutePath().toString());
Files.delete(p);
}else if(p.toFile().isDirectory()){
for(Path subPath:Files.newDirectoryStream(p)){
delHelp(subPath);
}
log.debug("delete directory:"+p.toAbsolutePath().toString());
Files.delete(p);
}
}
On unix-like system, it works out. On windows, the code Files.delete(p) actually move the directory to the trash can, so when delete the parent directory the code will throw exception: Exception in thread "main" java.nio.file.DirectoryNotEmptyException
Any idea about this os-dependent behavior? How can I work around this?
The actual problem is that you are not closing the DirectoryStream, which is causing the DirectoryNotEmptyException when you try to delete the directory.
From the Javadoc:
When not using the try-with-resources construct, then directory stream's close method should be invoked after iteration is completed so as to free any resources held for the open directory.
So you can either call close() on it when you are done with it, or use it in try-with-resources:
private static void delHelp(Path p) throws IOException {
if (!p.toFile().exists()) {
return;
} else if(p.toFile().isFile()){
Files.delete(p);
} else if(p.toFile().isDirectory()){
try (DirectoryStream<Path> ds = Files.newDirectoryStream(p)) {
for (Path subPath : ds){
delHelp(subPath);
}
}
Files.delete(p);
}
}
please first of all add this Jar into your project first.
Find below code works perfectly as per your requirement too.
i.e. work on window machine and should be not goes to trash/recycle-bin
public static void main(String[] args) {
try {
delDirectory("E:\\RecursiveDataContainDirectoryName");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void delDirectory(String path) throws IOException {
Path p = Paths.get(path);
FileDeleteStrategy.FORCE.delete(p.toFile());
}

How can i do to get all class of a given package with guava

I am working on a maven project and I added to my pom.xml file the guava dependency and the dependency of an other project. I want to get all class of a given package of that project which I have added to my pom as a dependency.
So I tried with this :
public void getClassOfPackage() {
final ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
try {
for (final ClassPath.ClassInfo info : ClassPath.from(loader)
.getTopLevelClasses()) {
System.out.println(info.getSimpleName());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new TestMain().getClassOfPackage();
}
And I know that is wrong because it gives that in console:
HierarchicalConfigurationConverter
HierarchicalConfigurationXMLReader
HierarchicalINIConfiguration
SubsetConfiguration
SystemConfiguration...
I don't know where I can specify the project where I am talking about and how I can just pass the package name and it gives me all class which it contains.
I can show all the classes whitch are in the same project but for an other project added as a dependency in pom.xml not yet :
The solution for what we i have in the same project:
public void getClassOfPackage() {
final ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
try {
ClassPath classpath = ClassPath.from(loader); // scans the class path used by classloader
for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses("org.mypackage")) {
System.out.println(classInfo.getSimpleName()+" <==> "+classInfo.getPackageName());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new TestMain().getClassOfPackage();
}
I found tow solutions :
With guava :
public void getClassOfPackage(String packagenom) {
final ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
try {
ClassPath classpath = ClassPath.from(loader); // scans the class path used by classloader
for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses(packagenom)) {
if(!classInfo.getSimpleName().endsWith("_")){
System.out.println(classInfo.getSimpleName());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new TestMain().getClassOfPackage("org.myproject");
}
With Java.util:
public List<Class> getClassOfPackage(String packageName)
throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<File> dirs = new ArrayList<File>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<Class>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes;
}
private static List<Class> findClasses(File directory, String packageName)
throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file,
packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName
+ '.'
+ file.getName().substring(0,
file.getName().length() - 6)));
}
}
return classes;
}
public static void main(String[] args) throws ClassNotFoundException,
IOException {
for (Class className : new ClassOfPackage()
.getClassOfPackage("org.mypackage")) {
if (!className.getSimpleName().endsWith("_")) {
System.out.println(className.getSimpleName());
}
}
}
This is why you're seeing it print out sun.misc.Launcher$AppClassLoader:
} else {
System.out.println(loader.getClass().getName());
}
Every class on your classpath that isn't in your package is causing your program to print out the name of the ClassLoader implementation class, which you probably don't want.
Also, while info.getName().startsWith("org.mypackage") should work, it might be preferable to write info.getPackageName().equals("org.mypackage") (or startsWith if you want to include subpackages too).
It is easier to solve this problem with the help of Google reflections.
Please check the following question for the correct answer - note that the checked answer does not provide a working solution, the second one (Aleksander Blomskøld) does!

Java getResource return null mac

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

Categories