Solution for ClassCastException due to a problem with ClassLoader

I have two ClassLoaders that load the same class. Thus, it is obvious that they cannot abandon each other. But I need to access an object created in another ClassLoader.

I have access to ClassLoaders. How can I use this object in another class? I do not need to throw the object in line with the current ClassLoader.

But the problem is that the return type is Object . So, I have to drop this object in order to access some methods. How can i do this? A normal action like the one below throws a ClassCastException, which I already know about.

 Mojo mojo = (Mojo) descriptor.getMojo(); 

descriptor#getMojo() returns an object of type Mojo , but the method returns Object . How can I do that?

Let me know if you need more information.

I read all theories about loading classes, but none of them indicated the correct solution for this.

+6
source share
5 answers

AFAIK, no, you cannot throw an object of a class loaded by one classloader into another classloader.

  • One solution would be to create a “generic” class loader that loads the classes that your class loaders will use. Therefore, in your case, you will have a new class loader that will load this class, and your custom class loaders will expand this class loader.
  • Another solution would be to transition around a “serialized” state between two class loaders. Serialize one instance into an array of bytes and restore the object in another class loader by de-serializing the stream of objects.
+7
source

Reflection is not so bad, and is appropriate here.
Is it a Maven plugin, BTW?

You need something like:

 Mojo mojo = (Mojo)descriptor.getClass().getMethod("getMojo").invoke(descriptor); 

I leave a lot - especially exception handling - but this should lead you to the Javadoc that you need. This is not bad, but read it carefully.

If you also have two Mojo classes, the cast will be broken and you will need to do more thinking to do whatever you need with the evil Mojo double.

+1
source

Why do you have 2 CloassLoaders that load the same class? This may be a programming issue. It looks like you're caching ClassLoader somewhere and reusing them incorrectly. If this is not the case, try MultiClassLoader.

Create a MultiClassLoader that includes several other class loaders. You can use these MultiClassLoader to load all the classes you want. But you need to create this MultiClassLoader at the very beginning, and not when loading classes.

 public class MultiClassLoader extends ClassLoader 

You will have a collection of class loaders, and in findClass (...) you iterate over all these registered loaders.

 protected Class findClass(String aName) throws ClassNotFoundException { for (Iterator iter = multiLoaders.iterator(); iter.hasNext();) { ClassLoader tmpLoader = (ClassLoader)iter.next(); try { return tmpLoader.loadClass(aName); } catch (ClassNotFoundException e) { } } throw new ClassNotFoundException(aName); } 
0
source

The easiest way is to use reflection. This allows you to do everything you can in “normal” code.

0
source

I think it is better to use an array of bytes instead of an object. While deserliazing, get an array of bytes back and convert to an object.

I had the same problem and working with a byte array worked.

 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = null; try { out = new ObjectOutputStream(bos); out.writeObject(cachedValue); byte b[] = bos.toByteArray(); //Store in DB, file wherever here using b[]. I am not writing code to store it as it may vary in your requirement. } catch (IOException e) { e.printStackTrace(); } 

Reading from a byte array:

 ByteArrayInputStream bis = new ByteArrayInputStream(<<read byte[] where you stored earlier>>); ObjectInput in = null; try { in = new ObjectInputStream(bis); <Your Class >cachedRes = ( Your Class) in.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } 
0
source

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


All Articles