ClassCastException при создании экземпляра класса с использованием отражения и ClassLoaders - PullRequest
5 голосов
/ 08 июня 2010

Прежде всего, это Java 1.4 (ограничения проекта). Я пытаюсь создать менеджер приложений. Он загружает основной класс каждого приложения, используя собственный экземпляр загрузчика классов. После этого он создает экземпляр основного класса, используя отражение. Каждое приложение реализует общий интерфейс, поэтому после создания экземпляра он запускает предопределенный метод приложения.

Однако у меня возникли некоторые проблемы в CRASH POINT 1 (см. Код). Класс не распознается как одна реализация его интерфейса. Если я закомментирую этот фрагмент кода, я получу ClassCastException в CRASH POINT 2.

Полагаю, обе ошибки связаны с одной и той же проблемой (конечно).

Кто-нибудь может мне помочь? Соответствующая часть кода следует (импорт удален) ...

Большое спасибо.

Marcus

// AppManager.java

public class AppManager {
    public ThreadGroup threadGroup;
    private Class appClass;
    private AppInstance appInst;
    public AppContextImpl context;

    private AppManager(CustomClassLoader cl, String mainClass) throws ClassNotFoundException {
        final String className = mainClass;
        final CustomClassLoader finalLoader = cl;

        appClass = cl.loadClass(mainClass);

        // DEBUG CODE:
        Class[] k1 = AppInstance.class.getInterfaces();
        System.out.println(k1.length + " interfaces for AppInstance.class:");
        for (int ii = 0; ii < k1.length; ii++) {
            System.out.println("   " + ii + " - " + k1[ii].getName() + " (" + k1[ii].getClassLoader() + ")");
        }

        Class[] k2 = appClass.getInterfaces();
        System.out.println(k2.length + " interfaces for appClass instance:");
        for (int ii = 0; ii < k2.length; ii++) {
            System.out.println("   " + ii + " - " + k2[ii].getName() + " (" + k2[ii].getClassLoader() + ")");
        }

        // CRASH POINT 1
        if (!(AppInstance.class.isAssignableFrom(appClass))) {
            throw new IllegalArgumentException("Attempt to run a non-AppInstance class: " + appClass);
        }

        context = new AppContextImpl(mainClass, this);
        cl.setAppManager(this);
        Constructor m;
        try {
            m = appClass.getConstructor(new Class[0]);
           // CRASH POINT 2
            appInst = (AppInstance) m.newInstance(new Object[0]);
            appInst.init(context);
        } catch (Exception e) {
            System.out.println("Got ClassCastException here!\n");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        App app1;

        String path1 = "/home/user/workspace/MultiTaskTest/bin/";
        String app1Name = "App1";

        Vector v1 = new Vector();
        try {
            v1.add(new URL(path1));
        } catch (MalformedURLException e1) {
            final File file1 = new File(path1);
            try {
                URL path1aux = (URL) AccessController.doPrivileged(
                    new PrivilegedExceptionAction() {
                        public Object run() throws IOException {
                            if (!file1.exists()) {
                                System.out.println("Warning: \"" + file1.getPath() + "\" not found");
                                return null;
                            }
                        return file1.toURI().toURL();
                        }
                    });

                if (path1aux != null) {
                    v1.add(path1aux);
                }
            } catch (PrivilegedActionException e) {
                e.getException().printStackTrace();
            }
    }

        final URL[] array1 = (URL[]) v1.toArray(new URL[v1.size()]);
        CustomClassLoader cl1 = (CustomClassLoader) AccessController.doPrivileged(
            new PrivilegedAction() { public Object run() {
                return new CustomClassLoader(array1);
            }});
        System.out.println("ClassLoader 1 created: " + cl1);
        try {
            app1 = new App(cl1, app1Name);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("Cannot find class App1.");
        }
    }
}

// AppInstance.java

public interface AppInstance {
    public void init(ContextImpl context);
}

// App1.java

public class App1 implements AppInstance {
    private AppContextImpl contextObj;

    public void init(AppContextImpl context) {
        this.contextObj = context;
        System.out.println("Running App1...");
    }
}

// AppContextImpl.java

public class AppContextImpl {
    public String mainClass;
    public AppManager app;

    public AppContextImpl(String mainClass, AppManager app) {
        this.mainClass = mainClass;
        this.app = app;
    }
}

// CustomClassLoader.java

public class CustomClassLoader extends URLClassLoader {
    AppManager appInst;

    public CustomClassLoader(URL[] paths) { super(paths, null); }
    public void setAppManager(AppManager app) { this.appInst = app; }
}

Выходные данные для кода отладки в файле AppManager.java:

0 interfaces for AppInstance.class:
1 interfaces for appClass instance:
   0 - AppInstance (CustomClassLoader@480457)

1 Ответ

4 голосов
/ 08 июня 2010

Ваш класс AppInstance, вероятно, загружается отдельно каждым пользовательским загрузчиком классов. Так как объекты класса зависят от фактического класса И от загрузчика классов, это действительно разные классы. Таким образом, AppInstance из загрузчика классов 1 отличается от AppInstance из загрузчика классов 2.

Что вам нужно сделать, это использовать стандартную иерархию загрузчика классов: используйте корневой загрузчик классов для своего приложения, и убедитесь, что AppInstance загружается загрузчиком классов. Затем сделайте свой пользовательский загрузчик классов из корня. Всякий раз, когда им нужно получить доступ к классу AppInstance, они будут использовать то, что загружено из корня.

Итак, вместо этого:

public CustomClassLoader(URL[] paths) { super(paths, null); }

Вам необходимо предоставить родителя вашему CustomClassLoader

...