ClassNotFoundException по време на десериализация на току-що сериализиран клас

Имах проблем с десериализацията на обект. Текущият проект има архитектура в стил плъгин, така че имам буркани, които съдържат клас файлове, които се зареждат по време на изпълнение. Не успях да десериализирам обект, който съдържа клас, който беше открит в един от тези буркани, така че написах метод за бърз тест, който се извиква по средата на потока, който току-що зареди плъгините, инстанцира правилния (обектът имплементира определен интерфейс така че мога да го идентифицирам чрез .isAssignableFrom(..)), сериализира го (което се случва добре) и след това веднага се опитва да го десериализира.

Все още получавам „ClassNotFoundException“.

Stacktrace:

Jul 21, 2014 4:02:11 PM com.newspinrobotics.auth.MainFrame loadPlugins
SEVERE: null
java.lang.ClassNotFoundException: com.newspinrobotics.auth.plugin.tcpserver.TCPServer
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:625)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1612)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.newspinrobotics.auth.MainFrame.loadPlugins(MainFrame.java:79)
at com.newspinrobotics.auth.MainFrame.<init>(MainFrame.java:43)
at com.newspinrobotics.auth.MainFrame$6.run(MainFrame.java:539)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Сега, преди да попитате. Класът TCPServer няма полета, които не могат да бъдат сериализирани. В него има низове и примитиви. Има едно поле, което не попада в тези категории, но е маркирано като преходно. Има дори конструктор без аргумент (въпреки че това не е необходимо, нали?). И да, той прилага Serializable (сериализацията върви добре).

Объркан съм как е възможно програмата за зареждане на класове да НЕ го има, тъй като инстанцира обекта само няколко реда, преди да го десериализира.

Използвам специално създаден ClassLoader (разширява URLClassLoader), за да заредя jar файловете по време на изпълнение.

Предоставям публичен статичен окончателен дълъг serialVersionUID = XXXXXXXL; поле.

РЕДАКТИРАНЕ:

Class loader, за който имам предвид, разширява URLClassLoader. Намира се вътре в полезен клас, написан от друг човек, който при по-нататъшна проверка всъщност дори не е модификация (по някаква причина му се искаше да го разшири и да не прави нищо съществено за него). Всичко, което помощната програма прави, е да раздели jar файлове и да използва URLClassLoader, за да добави jar файловете в URLClassLoader чрез addURL(..) и също така да зареди класовете чрез loadClass(..). Така че не изглежда, че има нещо лошо в тази помощна програма. Аз обаче не съм нинджа на ClassLoader, така че със сигурност мога да дам допълнителна информация за това, ако е необходимо. Това всъщност са само няколко помощни функции за зареждане на Jar файлове и избиране на клас файлове и тяхното зареждане.

Помогнете ми StackOverflow, вие сте единствената ми надежда (може би).


person Aaron Marcus    schedule 21.07.2014    source източник
comment
Така че сте внедрили персонализиран ClassLoader, имате проблем със зареждането на класове и не публикувате нито един от кодовете си за зареждане на класове (нито персонализирания ClassLoader, нито кода, който го използва, включително кода, който изгражда TCPServer обект на първо място)...   -  person Tim    schedule 22.07.2014
comment
Добре. Като се има предвид, че ClassLoader изглежда работи за инстанциране на обектите (по такъв начин, че те са напълно използваеми), не изглежда, че проблемът е в зареждащия клас.   -  person Aaron Marcus    schedule 22.07.2014
comment
Вашият персонализиран Classloader не изглежда да е в проследяването на стека ви, което го кара да изглежда, че не се използва, когато десериализирате. Така че, въпреки че може да е добре, кодът, който се опитва да го използва (чрез ObjectInputStream), изглежда не е такъв. Можете ли да публикувате съответния код?   -  person Tim    schedule 22.07.2014
comment
Какво смятате за уместно? Цялата помощна програма за зареждане на клас? или определението за „модифицирано зареждане на класове“, което наистина в крайна сметка изобщо не е модифицирано. Той е разширен, но само заменя addURL и в това просто извикайте super. Така че изобщо не е удължен.   -  person Aaron Marcus    schedule 22.07.2014
comment
Бих бил по-малко загрижен за самия ClassLoader (защото, както казвате, той работи другаде) и повече за кода, където го извиквате. Така че, ако нашата дискусия относно разширяването на ObjectInputStream в коментарите към моя отговор не даде резултат, бих ви предложил да публикувате кода, където успешно инстанциирате TCPServer от вашия зареждащ клас, както и кода, където го десериализирате неуспешно от ObjectInputStream (включително кода, където създавате и конфигурирате този ObjectInputStream). Но се надяваме, че разширяването на ObjectInputStream ще бъде всичко, от което се нуждаете.   -  person Tim    schedule 22.07.2014


Отговори (1)


Подкласирахте ли ObjectInputStream, за да замените resolveClass(), за да използвате вашия персонализиран Classloader? (За пример на някой друг, който прави това, но не е директен отговор на вашия въпрос, вижте Проблем с десериализацията на персонализирания зареждач на класове на ObjectInputStream: resolveClass() не е извикан.)

person Tim    schedule 21.07.2014
comment
Не, не съм подкласирал ObjectInputStream, просто използвах по подразбиране. Изобщо не съм мислил за това взаимодействие. - person Aaron Marcus; 22.07.2014
comment
Самият аз не съм правил това, но малкото търсене в Гугъл, което направих, изглежда показва, че това е, което се прави най-често. (Може да има други начини да го направите, не съм сигурен.) Предполагам, че стандартният ObjectInputStream просто извиква стандартния зареждащ клас, като не ви дава начин да инжектирате персонализирания зареждащ клас в средата на повикването. Малко съм изненадан, че няма API за предаване на набор от персонализирани ClassLoaders към стандартен ObjectInputStream, но може би това ще се появи в бъдеще. - person Tim; 22.07.2014
comment
съжалявам Забравих да щракна. Да, това беше проблем със зареждането на класове. Трябваше да се направи персонализиран ObjectInputStream, за да се поправи. - person Aaron Marcus; 30.07.2014
comment
Здравей, @AaronMarcus, как и къде внедри този персонализиран ObjectInputStream? Тук сме изправени пред абсолютно същия проблем: stackoverflow.com/questions/66663334/ - person Mario Marinato; 17.03.2021