两个类加载器;一个类加载器需要丢弃一个对象,但其他类加载器不允许它



我正在尝试引用通过类加载器加载的对象,该对象位于由另一个类加载器加载的类中。我需要执行该对象的强制转换才能访问某些方法。我需要一种方法来避免其他类加载器来进行此转换。我知道我们不能投射不同类加载器的类,这不是我在这里需要的。我需要在同一个类加载器中进行转换,避免加载了同一类的另一个类加载器。结果真的很困难。

这里有一点背景。正如你在下面的类中看到的,我通过方法ComponentResolver.lookup((在MyClass.configure((方法接收一个对象,该方法是Mojo的一个实例,但被强制转换为Object。

不幸的是,Mojo mojo = clazz.cast(o)(在下面的MyClass中(失败并出现编译错误,表示返回的clazz.cast类型是Object。谁能告诉我如何解决这个问题?可能是通过相同的 Class#cast 方法或通过反射?不过我对反思不太熟悉!

//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();
       }
}
就 JVM 而言,由

classloader 加载的 Mojo 类和其他类加载器加载的Mojo类是完全不同的类。

一些选项:

  • 通过反射在调用方法等方面做任何你需要做的事情
  • 通过反射基于现有Mojo创建一个新,然后使用它(这取决于Mojo真正在做什么(
  • 更改类装入器层次结构,以便一个类装入
  • 器委托给另一个类装入器,以便您可以直接转换。

你处于一个根本上令人讨厌的位置,我知道没有简单的解决方法。如果你修复类加载器层次结构,它会让你的生活更轻松。只需在类加载器中Mojo,其他两个类加载器都作为其父类加载器就足够了。

这是奇怪的想法,并且增加了使用此类类的许多限制。

如果你的第二个类加载器

只加载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 - 获取字段的值; 创建分层 - 使用对象序列化实例化方法通过类创建对象。

但正如我之前所说,这种方法只有在您的类非常简单时才有效。不应该有由另一个类加载器加载的类型字段,你不应该在构造函数中具有基于fileds值的复杂逻辑,并且你应该明白新对象将包含所有字段对现有对象的引用。

最新更新