бросить через загрузчик классов? - PullRequest
22 голосов
/ 07 апреля 2010

Как я могу это сделать:

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
  }
}

Мне нужно, чтобы JVM рассмотрела экземпляр Foo из cl, как если бы он был экземпляром Foo из загрузчика классов исполняемого кода.

Я видел эти подходы, ни один из них не подходит мне (приведенный выше пример является игрушечным):

  1. Загрузка класса (или отдельного интерфейса) загрузчиком классов, который является родительским для вызывающего кода и созданного загрузчика классов
  2. Сериализация и десериализация объекта.

Ответы [ 6 ]

25 голосов
/ 07 апреля 2010

Не возможно. Идентификатор класса состоит из полностью определенного имени и загрузчика класса.

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

8 голосов
/ 18 января 2013

Я только что провел последние два дня, пытаясь решить эту проблему, и, наконец, я обошёл проблему, используя 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[] {});
}

Надеюсь, это кому-нибудь поможет.

6 голосов
/ 20 октября 2016

Если класс, который нужно привести, реализует Serializable, то:

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);
3 голосов
/ 07 апреля 2010

Возможно, что-то с использованием интерфейсов и java.lang.reflect.Proxy подойдет вашим предпочтениям. Использование InvocationHandler, которое находит и вызывает соответствующий метод в целевом классе. (Обратите внимание, что если вы это сделаете, все ваши мобильные коды безопасности будут проверены.)

2 голосов
/ 14 января 2016

Нет возможности разыграть в другом загрузчике классов.

У вас есть обходной путь с Gson, пример приведения Object к YourObject (Object является классом YourObject, но в другом classLoader):

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

Я использую этот обходной путь, потому что я компилирую любой код Java в WebApp (на Tomcat). Этот обходной путь запущен в производство.

0 голосов
/ 25 апреля 2015

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

На самом деле это работает, если и 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>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...