Loading a class not dynamically in a classpath in a web application - without using a custom class loader

I am developing a web application.

  • The web application generates Java classes on the fly. For example, it generates the class com.people.Customer.java
  • In my code, I dynamically compile this to get com.people.Customer.class and store in some directory say repository/com/people/Customer.class , which is not in the classpath of my application server. My application server (I use WebSphere Application Server / Apache Tomcat, etc.) Selects classes from the WEB-INF/classes directory. The Loader class would use this to load classes.
  • After compiling, I need to load this class so that it becomes available to other classes that use it after it is created.
  • When I use Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer) , it is obvious that Classloader cannot load the class because it is not in the classpath (not in WEB-INF/classes ). For similar reasons, getResource(..) or getResourceAsStream(..) also does not work.

I need a way:

Read the Customer.class class, possibly as a stream (or in any other way), and then load it. The following are limitations:

  • I cannot add the repository folder to the WEB-INF/classes folder.
  • I cannot create a new Custom ClassLoader. If I create a new ClassLoader and it loads the class, it will not be available for its parent ClassLoader.

Is there any way to achieve this?

If this is not the case, in the worst case, there is a way to override the default class loader using a special class loader for web applications, the same class loader should be used to load applications throughout the life cycle of my web application.

Rate any solution :)

+4
source share
3 answers

To do this, you need a special class loader, and in this class loader you need to override the findClass(String name) method

Example:

 public class CustomClassLoader extends ClassLoader { final String basePath = "/your/base/path/to/directory/named/repository/"; @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { String fullName = name.replace('.', '/'); fullName += ".class"; String path = basePath + fullName ; try { FileInputStream fis = new FileInputStream(path); byte[] data = new byte[fis.available()]; fis.read(data); Class<?> res = defineClass(name, data, 0, data.length); fis.close(); return res; } catch(Exception e) { return super.findClass(name); } } } 

Then you will load the classes from a custom location. For instance:

 Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader()); Object obj = clazz.newInstance(); 

By doing this, you tell the JVM that a class named my.pretty.Clazz must be loaded by your custom classloader, which knows how and where from to load its own class. It resolves the fully qualified class name (for example, my.pretty.Clazz ) to the file name (in our case: /your/base/path/to/directory/named/repository/my/pretty/Clazz.class ), then loads the resulting resource into as a byte array and finally converts this array into an instance of Class .

This example is very simple and demonstrates the general method of loading custom classes, as in your case. I suggest you read some articles about loading classes, like this one .

+2
source

Short answer: No

Without a special ClassLoader, you cannot dynamically load classes.

However, your assumption that you cannot use your own ClassLoader because your other objects loaded by WebApp ClassLoader will not be able to use these newly loaded classes is incorrect. All you need is a general way to use these newly created classes — as a common interface or meta description (Beans Introspector for accessing bean properties).

But if you use third-party libraries, such as Hibernate, and you dynamically load objects at runtime that should be stored, then it will be difficult for you, but imho is possible.

+1
source

Of course you can do it. Just get the network class loader and call the defineClass () method with reflection (it's protected, so be sure to call setAccessible (true) in the method. DefineClass () takes a byte array, so it doesn't matter where you are from. Make sure the name The class is unique and you only load it once, or you will have problems loading classes.

+1
source

Source: https://habr.com/ru/post/1304515/


All Articles