Два загрузчика классов;Один загрузчик классов должен свергнуть объект, но другой загрузчик классов не позволяет ему - PullRequest
1 голос
/ 20 августа 2011

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

Вот небольшой контекст.Как видно из приведенных ниже классов, я получаю объект в методе MyClass.configure () через метод ComponentResolver.lookup (), который является экземпляром Mojo, но приведен к Object.

К сожалению, Mojo mojo = clazz.cast(o) (в MyClass ниже) завершается с ошибкой компиляции, говоря, что возвращаемый тип clazz.cast - Object.Может кто-нибудь сказать мне, как решить эту проблему?Может быть, с помощью того же метода класса # или с помощью отражения?Я не очень хорошо знаком с отражением!

//This is loaded by, say ClassLoader X
public class ComponentResolver {
    public Object lookup(String role) {

        //do something
        return component;     //component is an instance of Mojo interface.
    }
}

Вот MyClass, где я вызываю метод поиска.

//This class including Mojo in this context is loaded by, say ClassLoader Y
public class MyClass {
    public void configure() {
        Object o = componentResolver.lookup("componentName");

//      Mojo mojo = (Mojo) o;  //causes classcastexception (obviously.)

        Class<?> clazz = Class.forName("org.Mojo", false,
                o.getClassLoader()   );

        Mojo mojo = clazz.cast(o);
    //Causes compiler errors because the returned object is of type Object. 
    //ie incompatible types Required:Mojo, Found:Object

       // Mojo mojo = (Mojo) clazz.cast(o); //again classcastexception.

        mojo.execute();
       }

}

Ответы [ 2 ]

2 голосов
/ 20 августа 2011

Класс Mojo, загружаемый вашим загрузчиком классов, и класс Mojo, загружаемый другим загрузчиком классов, - это совершенно разные классы в отношении JVM.

Некоторые параметры:

  • Делайте все, что вам нужно с точки зрения вызова методов и т. Д. С помощью отражения
  • Создайте новый Mojo на основе существующего с помощью отражения, а затем используйте его (это зависит от того, что на самом деле делает Mojo)
  • Измените иерархию загрузчика классов так, чтобы один загрузчик классов делегировал другому, так что вы можете просто разыграть.

Вы находитесь в принципиально неприятном положении, а * 1017 нет* легкий обходные пути, о которых я знаю.Если вы сможете возможно исправить иерархию загрузчиков классов, это сделает вашу жизнь на лот проще.Достаточно иметь Mojo в загрузчике классов, который оба других загрузчика классов имеют в качестве родителя.

0 голосов
/ 28 ноября 2013

Это странно думать и добавляет много ограничений при использовании таких классов.

Если ваш второй загрузчик классов загружает только Mojo и все другие типы полей, загруженные первым загрузчиком классов, вы можете создать еще один объект класса, загруженный вторым загрузчиком классов, и скопировать в него значения всех полей.

@NotNull
public static <T> T copy(@NotNull Class<T> targetClass,
                         @NotNull Object original) throws ReflectionException {
  try {
    final T other = createHierarchical(targetClass);
    Class<?> aClass = ruleClass;
    Class<?> oClass = original.getClass();
    while (aClass != null && oClass != null) {
      for (Field otherField : aClass.getDeclaredFields()) {
        if (Modifier.isStatic(otherField.getModifiers()))
          continue;
        final Field originalField = oClass.getDeclaredField(otherField.getName());
        Object value = getFieldValue(original, originalField);
        final Class<?> otherFieldType = otherField.getType();
        if (!otherFieldType.isPrimitive() && value != null 
            && !otherFieldType.isAssignableFrom(value.getClass())) {
          value = copy(otherFieldType, value);
        }
        hackField(other, otherField, value);
      }
      aClass = aClass.getSuperclass();
      oClass = oClass.getSuperclass();
    }
    if (aClass != null || oClass != null)
      throw new ReflectionException("Class has not identical hierarchy");
    return other;
  } catch (NoSuchFieldException e) {
    throw new ReflectionException(e);
  }
}

В этом коде: hackField - установить значение в поле любого вида, даже если оно недоступно или окончательно; getFieldValue - получить значение поля; createHierarchical - создает объект через класс, используя метод моментализации сериализации объекта.

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

...