Решение для ClassCastException из-за проблемы ClassLoader - PullRequest
6 голосов
/ 16 августа 2011

У меня есть два ClassLoaders, которые загружают один и тот же класс. Итак, очевидно, что они не могут передаваться друг другу. Но мне нужно получить доступ к объекту, созданному в другом ClassLoader.

У меня есть доступ к обоим ClassLoaders. Как я могу использовать этот объект в другом классе? Мне не нужно приводить объект в соответствие с текущим ClassLoader.

Но проблема в том, что тип возвращаемого объекта Object. Итак, я должен бросить этот объект, чтобы получить доступ к некоторым методам. Как я могу это сделать? Обычное приведение типа, как показано ниже, вызывает ClassCastException, который я уже знаю.

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

descriptor#getMojo() возвращает объект типа Mojo, но метод возвращает Object. Как это сделать?

Дайте мне знать, если вам нужна дополнительная информация.

Я прочитал все теории о загрузке классов, но ни одна не определила правильного решения для этого.

Ответы [ 5 ]

8 голосов
/ 16 августа 2011

AFAIK, нет, вы не можете привести объект класса, загруженного одним загрузчиком классов в другой загрузчик классов.

  • Одним из решений было бы создание "общего" загрузчика классовкоторый загружает классы, которые будут использоваться вашими пользовательскими загрузчиками классов.Таким образом, в вашем случае у вас будет новый загрузчик классов, который будет загружать данный класс, а ваши пользовательские загрузчики классов расширят этот загрузчик классов.
  • Другое решение - обойти «сериализованное» состояние между двумя загрузчиками классов.Сериализуйте один экземпляр в байтовый массив и восстановите объект в другом загрузчике классов путем десериализации потока объекта.
1 голос
/ 17 августа 2011

Отражение не так уж и плохо, и здесь уместно.
Кстати, это плагин Maven?

Вы хотите что-то вроде:

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

Я упускаю многое - особенно обработку исключений - но это должно привести вас к Javadoc, который вам нужен. Это неплохо, но читайте внимательно.

Если у вас также есть два класса Моджо, актерский состав прервется, и вам придется больше размышлять, чтобы делать все, что вам нужно, с Моджо-злым близнецом.

0 голосов
/ 25 января 2018

Я думаю, что лучше вариант просто хранить байтовый массив вместо объекта. При удалении верните байтовый массив и преобразуйте его в объект.

У меня была та же проблема, и подход с байтовым массивом работал.

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();
    }

Чтение из байтового массива:

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 голосов
/ 16 августа 2011

Самый простой способ - использовать отражение.Это позволяет вам делать все, что можно, в «нормальном» коде.

0 голосов
/ 16 августа 2011

Почему у вас есть 2 CloassLoaders, которые загружают один и тот же класс? Это может быть программной проблемой. Похоже, вы где-то кешируете ClassLoader и неправильно используете их. Если это не так, попробуйте MultiClassLoader.

Создание MultiClassLoader, который включает несколько других загрузчиков классов. Эти MultiClassLoader вы можете использовать для загрузки всех классов, которые вы хотите. Но вы должны создавать эти MultiClassLoader в самом начале, а не при загрузке классов.

public class MultiClassLoader extends ClassLoader

У вас будет коллекция загрузчиков классов, и в findClass (...) вы перебираете все эти зарегистрированные загрузчики.

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);
}
...