ClassLoader: how to load a class from another project

I want to access a class from another project using ClassLoader. How can I indicate the path to this class and get this class file?

I want to be able to do this with code, as I upload many different class files through my application, and the path for different classes will constantly change.

I use CustomClassLoader, which loads class files, but only if they are in a project and not in another project

import java.io.FileInputStream; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedExceptionAction; public class CustomClassLoader extends ClassLoader { String repoLocation = "C:/TempBINfolder/bin/"; public CustomClassLoader() { } public CustomClassLoader(ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { AccessControlContext acc = AccessController.getContext(); try { return (Class) AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { FileInputStream fi = null; try { String path = name.replace('.', '/'); fi = new FileInputStream(repoLocation + path + ".class"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; // a big chunk int read; while ((read = fi.read(buffer)) > 0) baos.write(buffer, 0, read); byte[] classBytes= baos.toByteArray(); return defineClass(name, classBytes, 0, classBytes.length); } catch (Exception e) { throw new ClassNotFoundException(name); } } }, acc); } catch (java.security.PrivilegedActionException pae) { return super.findClass(name); } } } 

Class call

 for (Class singleClass : listOfClasses) { try { ClassLoader classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader()); Class stringClass = null; try { stringClass = classLoader.loadClass(singleClass.getName()); } catch (ClassNotFoundException ex) { Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex); } try { stringClass.newInstance(); } catch (InstantiationException ex) { Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex); } Class cls = Class.forName(stringClass.getName()); 

If I try to do Class cls = Class.forName(stringClass.getPackage()+"."+stringClass.getName()); the package will be null

EDIT: the following worked for me

 URL classUrl; classUrl = new URL("file:///"+ccl.getRepoLocation()); //This is location of .class file URL[] classUrls = {classUrl}; URLClassLoader ucl = new URLClassLoader(classUrls); Class cls = ucl.loadClass(stringClass.getName()); // Current .class files name 
+4
source share
3 answers

Use URLClassLoader to do this for you.

+2
source

This code looks good (I did something similar a long time ago). Although there is a small error:

If you do

 byte[] classBytes = new byte[fi.available()]; fi.read(classBytes); 

You read as many bytes as there are bytes available without blocking. This, you are not reading the entire file. In fact, the read method does not guarantee that the full byte buffer will be read.

Try to do:

 ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; // a big chunk int read; while ((read = fi.read(buffer)) > 0) baos.write(buffer, 0, read); byte[] bytesClass = baos.toByteArray(); 

or use Streams.copy from Apache. This is a convenient way to do the same.

Package definition

ClassLoader has a definePackage method. I would argue that you should name this method for every new package that you need. Otherwise, ClassLoader cannot determine the package, but from the full name of the class it seems that this is not enough.

So, the code will achieve this:

 // being package the name of the package for the new class // being definedPackages a Set<String> member of the classloader if (!this.definedPackages.contains(package)) { definePackage(package,"","","","","","",null); this.definedPackages.add(package); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; // a big chunk int read; while ((read = fi.read(buffer)) > 0) baos.write(buffer, 0, read); byte[] bytesClass = baos.toByteArray(); 
+2
source

Thanks for the above code that helped me.

SUB: calling the same class in two different places

I have a class that says Abc in the jar file of the classpath file, and dynamically I generate the same Abc class in the local directory with some code changes.

I need to create an instance and use the Abc class in the local directory. Below is the working code,

the CustomClassLoader class extends ClassLoader {

 String repoLocation = "./"; //C:/TempBINfolder/bin/ CustomClassLoader() { } CustomClassLoader(ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { AccessControlContext acc = AccessController.getContext(); try { return (Class) AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { FileInputStream fi = null; try { String path = name.replace('.', '/'); fi = new FileInputStream(repoLocation + path+ ".class"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; // a big chunk int read; while ((read = fi.read(buffer)) > 0) baos.write(buffer, 0, read); byte[] classBytes= baos.toByteArray(); return defineClass(name, classBytes, 0, classBytes.length); } catch (Exception e) { throw new ClassNotFoundException(name); } } }, acc); } catch (java.security.PrivilegedActionException pae) { return super.findClass(name); } } } 

calling the CustomClassLoader class,

  ClassLoader classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader()); Class stringClass = (new CustomClassLoader(ClassLoader.getSystemClassLoader())).findClass(packageName+"."+javaFileName); Object t = (Object) stringClass.newInstance(); 

Thanks Murwath

0
source

All Articles