代码之家  ›  专栏  ›  技术社区  ›  IttayD

穿越类加载器?

  •  20
  • IttayD  · 技术社区  · 16 年前

    我该怎么做:

    class Foo {
      public static Foo get() throws Exception {
        ClassLoader cl = new URLClassLoader(new URL[]{"foo.jar"}, null); // Foo.class is in foo.jar
        return (Foo)cl.loadClass("Foo").newInstance(); // fails on class cast
      }
    }
    

    我见过这些方法,但没有一个对我有好处(上面的例子是一个玩具的例子):

    1. 通过类加载器加载类(或单独的接口),该类加载器是调用代码和创建的类加载器的父类
    2. 序列化和反序列化对象。
    6 回复  |  直到 16 年前
        1
  •  28
  •   Michael Borgwardt    14 年前

    不可能。类标识由完全限定名和类装入器组成。

    将对象强制转换为由不同类加载器加载的具有相同名称的类与尝试强制转换 String Integer

        2
  •  9
  •   viragoboy    13 年前

    我刚刚花了两天的时间来解决这个问题,最后通过使用java反射解决了这个问题:

    // 'source' is from another classloader
    final Object source = events[0].getSource();
    
    if (source.getClass().getName().equals("org.eclipse.wst.jsdt.debug.internal.core.model.JavaScriptThread")) {
    
        // I cannot cast to 'org.eclipse.wst.jsdt.debug.internal.core.model.JavaScriptThread'
        // so I invoke the method 'terminate()' manually
        Method method = source.getClass().getMethod("terminate", new Class[] {});
        method.invoke(source, new Object[] {});
    }
    

    希望这对别人有帮助。

        3
  •  8
  •   wit    9 年前

    如果需要强制转换的类实现可序列化,则:

    private <T> T castObj(Object o) throws IOException, ClassNotFoundException {
        if (o != null) {
            ByteArrayOutputStream baous = new ByteArrayOutputStream();
            {
                ObjectOutputStream oos = new ObjectOutputStream(baous);
                try {
                    oos.writeObject(o);
                } finally {
                    try {
                        oos.close();
                    } catch (Exception e) {
                    }
                }
            }
    
            byte[] bb = baous.toByteArray();
            if (bb != null && bb.length > 0) {
                ByteArrayInputStream bais = new ByteArrayInputStream(bb);
                ObjectInputStream ois = new ObjectInputStream(bais);
                T res = (T) ois.readObject();
                return res;
            }
        }
        return null;
    }
    

    用法:

    Object o1; // MyObj from different class loader
    MyObj o2 = castObj(o1);
    
        4
  •  4
  •   Stéphane GRILLON    10 年前

    无法在不同的类加载器中强制转换。

    你有这个 变通办法 对于Gson,示例将对象强制转换为YourObject(Object是YourObject类,但在其他类加载器中):

    Object o = ... 
    Gson gson = new Gson();
    YourObject yo = gson.fromJson(gson.toJson(o), YourObject.class);
    

    我使用这种变通方法是因为我在WebApp(在Tomcat上)中编译任何java代码。此解决方案在生产中运行。

        5
  •  3
  •   Tom Hawtin - tackline    16 年前

    也许是一些使用接口和 java.lang.reflect.Proxy InvocationHandler 在目标类上查找并调用相关方法的(注意,如果您这样做,您拥有的任何移动代码安全性都将被穿透。)

        6
  •  0
  •   Qix - MONICA WAS MISTREATED    10 年前

    这是一个旧的职位,我到达,因为我想做几乎相同的事情,但一个更简单的版本。。。

    如果Foo和加载的类(在我的例子中来自另一个包中的.java类文件)都扩展同一个类,比如AbstractTestClass,那么它实际上可以工作。

    代码片段:

    public AbstractTestClass load(String toLoad) {
        try{
            Class test = Class.forName("testsFolder.testLoadable");
            Constructor ctorlist[] = test.getDeclaredConstructors();
            for(Constructor aConstructor : ctorlist){
               if(...){// find the good constructor
                  Object loadedTest = aConstructor.newInstance(new Object[]{/*params*/});
                  return (AbstractTestClass) test;
               }
            }
        }catch(...){}
        return new defaultTestClass();
    }
    

    ArrayList<AbstractTestClass>