Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / ClassCastException кастомизации класслоадинга / 13 сообщений из 13, страница 1 из 1
11.01.2017, 23:46
    #39382772
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
Почитал про класслоадинг в java и побаловался на примере.

Один момент остался не ясен.

Вот написал я свой кастомный класслоадер, парентом которого является System Classloader.


также имеется интерфейс MyInterface и класс MyInterfaceImpl(имплементация этого интерфейса)

пишу свой Main класс, в main которого, гружу MyInterface обычным образом то есть Системным класслоадером, а MyInterfaceImpl с помошью кастомного класслоадера.

в этом же методе кастую MyInterfaceImpl к MyInterface. Всё ок.

Если подгрузить MyInterfaceImpl тоже через кастомный класслоадер, то вываливается ClassCastException. Там где я это вычитал это подается как то, что Main не имеет доступа к MyInterfaceImpl так как они загружены разными класслоадерами. А почему скастить классы загруженный разными класслоадерами можно? в чем разница?
...
Рейтинг: 0 / 0
12.01.2017, 08:10
    #39382855
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
questioner Там где я это вычитал это подается как то, что Main не имеет доступа к MyInterfaceImpl
Вы опять читаете какую-то ерунду, либо странно её интерпретируете. Вопрос вообще не в доступе. Класс в JVM идентифицируется в том числе загрузчиком. Поэтом один и тот же класс с одним и тем же байт-кодом, загруженый разными загрузчиками, это формально два разных класса. Всё.


questionerА почему скастить классы загруженный разными класслоадерами можно? в чем разница?
Разница в том как грузится MyInterface. Либо он грузится один раз родительским, тогда дочерний загрузчик делегирует поиск родителю и использует класс загруженый им. Либо MyInterface грузится два раза, если загрузчик не имеет родителя, либо не делегирует ему поиск.
...
Рейтинг: 0 / 0
12.01.2017, 13:18
    #39383102
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
Blazkowicz,

Blazkowicz Класс в JVM идентифицируется в том числе загрузчиком. Поэтом один и тот же класс с одним и тем же байт-кодом, загруженый разными загрузчиками, это формально два разных класса. Всё.


Это понятно. Это я и раньше знал.
BlazkowiczquestionerА почему скастить классы загруженный разными класслоадерами можно? в чем разница?
Разница в том как грузится MyInterface. Либо он грузится один раз родительским, тогда дочерний загрузчик делегирует поиск родителю и использует класс загруженый им. Либо MyInterface грузится два раза, если загрузчик не имеет родителя, либо не делегирует ему поиск.

Я приведу конкретный код:

код кастомного загрузчика(его особенность в том, что он смотрит на маппинг и если маппинг присутствует, то будем грузить нашим лоадером):




Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
class XLoader extends ClassLoader {

    // карта отображения имен классов на файлы .class, где хранятся их определения
    HashMap<String, String> mappings;

    XLoader(HashMap mappings) {
        this.mappings = mappings;
    }


    public synchronized Class loadClass(String name) throws ClassNotFoundException {
        try {
            // важно!
            // приоритет отдан именно загрузке с помощью встроенного загрузчика

            if (!mappings.containsKey(name)) {
                System.out.println("loadClass (" + name + ") with parent classloader");
                return super.findSystemClass(name);
            }
            System.out.println("loadClass (" + name + ") with XLoader");
            String fileName = mappings.get(name);
            FileInputStream fin = new FileInputStream(fileName);
            byte[] bbuf = new byte[(int) (new File(fileName).length())];
            fin.read(bbuf);
            fin.close();
            return defineClass(name, bbuf, 0, bbuf.length);

        } catch (IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException(e.getMessage(), e);
        }
    }
}



класс и интерфейс:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
public class SexyClassForLoader implements ISexyInterface {

    public static String stat_foo = "hello stat_foo";


    static {
        System.out.println("SexyClassForLoader$$static");
    }


    public SexyClassForLoader() {
        System.out.println("SexyClassForLoader$$init");
    }


    public static String getStatFoo() {
        return stat_foo;
    }


    public String getSimpleFoo() {
        return simple_foo;
    }
    public String simple_foo = "hello simple_foo";


    public void makeBar() {
        System.out.println("make bar");
    }

}


Код: java
1.
2.
3.
4.
5.
public interface ISexyInterface {

    public void makeBar ();

}



содержимое main метода:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
        HashMap<String, String> mappings = new HashMap();
        mappings.put("sur.che.SexyClassForLoader", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\SexyClassForLoader.class");
        // if comment this line you will see
        mappings.put("sur.che.ISexyInterface", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\ISexyInterface.class");

        XLoader xloa = new XLoader(mappings);
        Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader");
        System.out.println("class was loaded with " + sexy_cla.getClassLoader());

        Object sexy_ob = sexy_cla.newInstance();
        System.out.println(sexy_ob.getClass().getClassLoader());
        System.out.println(ISexyInterface.class.getClassLoader());
        Thread.sleep(100);
        ISexyInterface local_sexy = (ISexyInterface) sexy_ob;
        local_sexy.makeBar();




output:

авторloadClass (sur.che.SexyClassForLoader) with XLoader
loadClass (sur.che.ISexyInterface) with XLoader
loadClass (java.lang.Object) with parent classloader
class was loaded with sur.che.XLoader@7f31245a
loadClass
(java.lang.System) with parent classloader
loadClass (java.io.PrintStream) with parent classloader
SexyClassForLoader$$static
SexyClassForLoader$$init
sur.che.XLoader@7f31245a
sun
.misc.Launcher$AppClassLoader@232204a1
Exception
in thread "main" java.lang.ClassCastException: sur.che.SexyClassForLoader cannot be cast to sur.che.ISexyInterface
at sur.che.Loader.main(Loader.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Если закомментировать строку:

Код: java
1.
mappings.put("sur.che.ISexyInterface", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\ISexyInterface.class");


то ошибка не валится:
авторloadClass (sur.che.SexyClassForLoader) with XLoader
loadClass (sur.che.ISexyInterface) with parent classloader
loadClass (java.lang.Object) with parent classloader
class was loaded with sur.che.XLoader@7f31245a
loadClass
(java.lang.System) with parent classloader
loadClass (java.io.PrintStream) with parent classloader
SexyClassForLoader$$static
SexyClassForLoader$$init
sur.che.XLoader@7f31245a
sun
.misc.Launcher$AppClassLoader@232204a1
make
ba
...
Рейтинг: 0 / 0
12.01.2017, 14:15
    #39383171
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
questionerЭто понятно. Это я и раньше знал.
Вопрос тогда в чём?

questionerЕсли закомментировать строку:то ошибка не валится:
Вы оперируете понятиями "ошибка есть" и "ошибка нет". Это просто жесть какая-то.
Поставьте брейк-поинт на строке где выбрасывается ClassCastException.
Найдите ISexyInterface внутри sexy_ob.getClass().getInterfaces() и сравните его с ISexyInterface.class. Увидите два разных класса.
...
Рейтинг: 0 / 0
12.01.2017, 14:52
    #39383211
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
BlazkowiczПоставьте брейк-поинт на строке где выбрасывается ClassCastException.
Найдите ISexyInterface внутри sexy_ob.getClass().getInterfaces() и сравните его с ISexyInterface.class. Увидите два разных класса.

авторsexy_ob.getClass().getInterfaces()[0].getClassLoader().getClass().getName()
=> sur.che.XLoader

авторISexyInterface.class.getClassLoader().getClass().getName()
=> sun.misc.Launcher$AppClassLoader

Да, это так, но как закомментированная строка то влияет на это поведение и почему?
...
Рейтинг: 0 / 0
12.01.2017, 15:00
    #39383220
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
questionerДа, это так, но как закомментированная строка то влияет на это поведение и почему?
Отладка через форум? Если класса нет в списке, XLoader его не грузит, а использует тот который у родителя. Выходит один экземпляр, а не два.
...
Рейтинг: 0 / 0
12.01.2017, 15:01
    #39383223
забыл ник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
сильно в коде не копался, но у вас есть строка

Код: java
1.
System.out.println(ISexyInterface.class.getClassLoader());



Предполагаю, что когда грузится класс мейн, то у вас там его импорт, потому он и грузится системным загрузчиком.
Вам или грузить мэйн кастомным класслоадером или не делать жестких импортов
...
Рейтинг: 0 / 0
12.01.2017, 15:07
    #39383233
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
забыл никсильно в коде не копался, но у вас есть строка
Код: java
1.
System.out.println(ISexyInterface.class.getClassLoader());


Предполагаю, что когда грузится класс мейн, то у вас там его импорт, потому он и грузится системным загрузчиком.
Вам или грузить мэйн кастомным класслоадером или не делать жестких импортов
Следующая строка
Код: java
1.
ISexyInterface local_sexy = (ISexyInterface) sexy_ob;


Точно так же заставит AppClassLoader грузить интерфейс.
...
Рейтинг: 0 / 0
12.01.2017, 15:22
    #39383249
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
в итоге получается, что:

Что явная загрузка класса ведет к загрузке интерфейса.
Если строка
Код: java
1.
mappings.put("sur.che.ISexyInterface", "D:\\java_things\\custom-classloader\\out\\production\\custom-classloader1\\sur\\che\\ISexyInterface.class");


закомментирована, то кастомный лоадер загрузить не сможет и будет использоваться лоадер приложения.
При попытке скастить используется интерфейс, который явно загружен лоадером нашего приложения и интерфейс, загруженный при загрузке класса.

Соответственно если строку раскомментировать, то будем сравнивать интерфейс загруженный нашим лоадером и интерфейс, загруженный лоадером приложения.

так?
...
Рейтинг: 0 / 0
12.01.2017, 15:32
    #39383266
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
questioner,

Вы путаете логику своего странноватого кода и логику загрузки.

1) Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader"); - насильно требуем загрузить класс
2) Класс реализует интерфейс, значит надо загрузить и интерфейс.
3) Грузим тем же XLoader, в котором нет делегации родителю, если интерфейс указан в списке mappings.
Итого имеем оба класса загружены XLoader-ом.
Родитель - AppClassLoader про XLoader ничего не знает. Поэтому тоже грузит ISexyInterface, так как он используется в методе.

Я бы посоветовал прочитать исходный код класса ClassLoader. Хотя бы метода loadClass(String, boolean). Но как мы выяснили в прошлой теме, это очень сложно. Так что, вероятно, совет лишен смысла.
...
Рейтинг: 0 / 0
12.01.2017, 15:48
    #39383285
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
Blazkowiczquestioner,

Вы путаете логику своего странноватого кода и логику загрузки.

1) Class sexy_cla = xloa.loadClass("sur.che.SexyClassForLoader"); - насильно требуем загрузить класс
2) Класс реализует интерфейс, значит надо загрузить и интерфейс.
3) Грузим тем же XLoader, в котором нет делегации родителю, если интерфейс указан в списке mappings.
Итого имеем оба класса загружены XLoader-ом.
Родитель - AppClassLoader про XLoader ничего не знает. Поэтому тоже грузит ISexyInterface, так как он используется в методе.

Я бы посоветовал прочитать исходный код класса ClassLoader. Хотя бы метода loadClass(String, boolean). Но как мы выяснили в прошлой теме, это очень сложно. Так что, вероятно, совет лишен смысла.

Так я то же самое и написал. разве нет?

когда пытаемся скастить к интерфейсу ведь наверное просматриваются getInterfaces() и получается, что интерфейсы разные по той причине, что загружены разными лоадерами.
...
Рейтинг: 0 / 0
12.01.2017, 15:56
    #39383295
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
questionerТак я то же самое и написал. разве нет?
Я уже перестаю удивлятся тому что на каждый ответ вы комментируете что вы уже в курсе.
...
Рейтинг: 0 / 0
12.01.2017, 16:27
    #39383339
questioner
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ClassCastException кастомизации класслоадинга
BlazkowiczquestionerТак я то же самое и написал. разве нет?
Я уже перестаю удивлятся тому что на каждый ответ вы комментируете что вы уже в курсе.

не обижайтесь.

У меня нет цели показать, что мол я и так всё знаю. Знал бы - сюда не написал бы. Но на мой взгляд я написал то же, что и Вы.
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / ClassCastException кастомизации класслоадинга / 13 сообщений из 13, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]