Dvě stejné třídy různých verzí (Java)

A. F.

Dvě stejné třídy různých verzí (Java)
« kdy: 18. 07. 2018, 04:53:28 »
Ahoj.

Něco málo jsem slyšel o class loaderech v javě. Ale nemám větší zkušenosti. Zajímalo by mě, zda zvládnou následující úlohu:

Mám třídu org.vendor.App z balíčku app-1.2.3.jar a pak jinou implementaci třídy org.vendor.App z balíčku app-1.2.1.jar. Je možné, nějakým způsobem načíst a vytvořit instance těchto dvou tříd tak, abych s nimi mohl pracovat najednou v jedné metodě?


Starous

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #1 kdy: 18. 07. 2018, 06:52:03 »
ano lze toho dosahnout nekolika zpusoby. Pokud používáš maven tak napr maven-shade-plugin umi vzit knihovnu a zmenit ji package tak aby se netloukli. Dalsi moznost je izolace classloaderu tak to delaji napr aplikacni servery - kazdou nacist jinym classloaderem - ale to pak je nebudes moc pouzit ze stejné třídy. Mozna jedine nejak pres reflexi.

Cronin

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #2 kdy: 18. 07. 2018, 06:58:07 »
Nijako normálne.

Nejako hodne šialene by to išlo cez reflection, ale musel by si obísť nielen štandardný spôsob načítavania a inštancionovania objektov, čo vlastne postup s použitím reflection robí by definition, ale naviac aj spôsob vyhľadania samotných tried. Ďalšie problémy môžu spôsobiť potenciálne konfliktné závislosti tých tried.

Pravdepodobne sa snažíš riešiť problém hodne zlým spôsobom. Buďto si použil java triedu tam, kde mali byť použité aplikačné údaje, alebo si mal na implementáciu dvoch verzií algoritmu použiť vhodný návrhový vzor, napr. stratégiu. Ale sa kompletne mýlim, všetko robíš správne, a skutočne máš problém, kde potrebuješ použiť naraz dve inštancie vzíduvšie z triedy rovnakého FQN ale inej verzie. V tom prípade potrebuješ niekoho, kto skutočne rozumie JVM internals a rýchlo pretransformuje aktuálny problém na jeden z problémov, ktoré som naznačil vyššie, aby niekto bez takých hlbokých znalostí mohol využiť na riešenie vzniknuvšieho štandarného problému štandardné postupy.

Cronin

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #3 kdy: 18. 07. 2018, 07:01:29 »
Ale sa kompletne mýlim, ...

*Alebo ...

ava

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #4 kdy: 18. 07. 2018, 08:54:23 »
Odpověď máš tady: https://stackoverflow.com/questions/11759414/java-how-to-load-different-versions-of-the-same-class

Croninovy příspěvky ohledně reflection si vymaž z hlavy, nedávají smysl.


zdenek henek nereg.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #5 kdy: 18. 07. 2018, 09:34:24 »
Ahoj.

Něco málo jsem slyšel o class loaderech v javě. Ale nemám větší zkušenosti. Zajímalo by mě, zda zvládnou následující úlohu:

Mám třídu org.vendor.App z balíčku app-1.2.3.jar a pak jinou implementaci třídy org.vendor.App z balíčku app-1.2.1.jar. Je možné, nějakým způsobem načíst a vytvořit instance těchto dvou tříd tak, abych s nimi mohl pracovat najednou v jedné metodě?

Urcite to jde jak je popsane v tom linku na stackoverflow, ale urcite to tak musis delat? Neni lepsi cesta? Jestli je to jen hack pred releasem a pak to predelas, tak ok, ale jestli to je styl, ktery chces prosazovat, tak se
ujisti, ze nikdo z kolegu nevi kde bydlis. Nemuseli by pak cteni a udzbu takoveho kodu psychicky unest a mohli by te chtit navstivit ...

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #6 kdy: 18. 07. 2018, 09:43:26 »
Zaměřil bych se na to, jestli a proč zrovna tohle potřebujete. Že máte závislost na dvou různých knihovnách a ty tranzitivně závisí na třetí knihovně, ale každá v jiné verzi (které jsou vzájemně nekompatibilní), to se stává. Ale že potřebujete obě dvě ty třídy v jedné metodě, to je opravdu divné.

Pak samozřejmě záleží na tom, co si můžete dovolit s těmi org.vendor.App dělat. Pokud od nich máte zdrojáky a můžete jednu verzi přesunout do jiného package, je to nejjednodušší řešení.

Pokud musíte vzít JARka tak jak jsou, je jediná možnost použít různé classloadery. Vaše třída ovšem bude nahraná jen jedním classloaderem, takže s těmi org.vendor.App nemůžete pracovat přímo, ale jen pomocí nějaké formy odkazů – lepší by bylo pomocí MethodHandle, ale nejsem si jistý, že to půjde, a nebo pomocí reflexe.

Každopádně bych se soustředil spíš na to, jak se tomu použití dvou různých verzí jedné třídy úplně vyhnout, než jak to udělat.

zdenek henek nereg.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #7 kdy: 18. 07. 2018, 09:43:46 »
Ahoj.

Něco málo jsem slyšel o class loaderech v javě. Ale nemám větší zkušenosti. Zajímalo by mě, zda zvládnou následující úlohu:

Mám třídu org.vendor.App z balíčku app-1.2.3.jar a pak jinou implementaci třídy org.vendor.App z balíčku app-1.2.1.jar. Je možné, nějakým způsobem načíst a vytvořit instance těchto dvou tříd tak, abych s nimi mohl pracovat najednou v jedné metodě?

Ciste teoreticky (pokud neni jar obfuscovany) tak by melo byt mozne udelat toto
1. decompiluj tridu
2. zmen package a jmeno tridy
3. proved znovu kompilaci, zabal to do jaru s dostatecne varovnym jmenem
4. uloz do maven repo a pouzivej jen tu tridu (popripade jeji zavislosti z app-1.2.1) a ne cely app-1.2.1.jar
a pak puzivej jen 1.2.3.jar

Timto zamezis existenci dvou trid se stejnym jmenem ve stejnem package.

Neco podobneho jsme delali, kdyz bylo potreba opravit bug v jaru, kde nebylo mozne kontaktovat dodavatele. Nastesti to nebylo obfuscovane a po case jsme se s dodavatelem dohodli na nove verzi jaru, ktery obsahoval i fix bugu.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #8 kdy: 18. 07. 2018, 10:13:00 »
Ahoj.

Něco málo jsem slyšel o class loaderech v javě. Ale nemám větší zkušenosti. Zajímalo by mě, zda zvládnou následující úlohu:

Mám třídu org.vendor.App z balíčku app-1.2.3.jar a pak jinou implementaci třídy org.vendor.App z balíčku app-1.2.1.jar. Je možné, nějakým způsobem načíst a vytvořit instance těchto dvou tříd tak, abych s nimi mohl pracovat najednou v jedné metodě?

Ciste teoreticky (pokud neni jar obfuscovany) tak by melo byt mozne udelat toto
1. decompiluj tridu
2. zmen package a jmeno tridy
3. proved znovu kompilaci, zabal to do jaru s dostatecne varovnym jmenem
4. uloz do maven repo a pouzivej jen tu tridu (popripade jeji zavislosti z app-1.2.1) a ne cely app-1.2.1.jar
a pak puzivej jen 1.2.3.jar

Timto zamezis existenci dvou trid se stejnym jmenem ve stejnem package.

Neco podobneho jsme delali, kdyz bylo potreba opravit bug v jaru, kde nebylo mozne kontaktovat dodavatele. Nastesti to nebylo obfuscovane a po case jsme se s dodavatelem dohodli na nove verzi jaru, ktery obsahoval i fix bugu.

Tohle ti udela maven nebo gradle automagicky, pokud potrebujes. Pluginy k tomu jsou, viz vyse.

(drobne varovani - ne nutne musi fungovat, pokud se do hry dostane Scala - https://www.scala-lang.org/old/sites/default/files/sids/dubochet/Mon,%202010-05-31,%2015:25/Storage%20of%20pickled%20Scala%20signatures%20in%20class%20files.pdf a pochopitelne pokud je ve hre nejaka reflexe je nutne byt obzvlast opatrny)

Karel

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #9 kdy: 18. 07. 2018, 10:47:36 »
Odpověď máš tady: https://stackoverflow.com/questions/11759414/java-how-to-load-different-versions-of-the-same-class

Croninovy příspěvky ohledně reflection si vymaž z hlavy, nedávají smysl.

Reflection je potřeba v situaci, kdy musíte použít tu třídu jako typ. Pokud proměnnou nebo parametr metody nadefinujete jako třídu ve verzi 1, pak do ní nejde vložit reference na třídu ve verzi 2. Musíte pak najít společného předka, kupříkladu Object, a na metody použít reflection.

V oblastech, kde se tohle "jedna třída ve více verzích" používá, se to ale obchází tím, že se použije interface. Ten může být nahraný default class loaderem a dokud ho obě verze používají, tak není žádný problém. Do proměnné/parametru typu interface se dají beztrestně použít obě verze té třídy.

Jo a pokud někoho zajímá, kde se to používá (spíše používalo) tak to byly systémy, kde se daly měnit zdrojové kódy za běhu. Kupříkladu Tomcat to možná dosud používá k tomu, aby uměl spustit novou verzi aplikace i bez restartu. Upravil jste třídu a aplikaci řekl, že je nová verze. Ta si ji pak natáhla novým classloaderem a nové instance pak byly už upravené. Samo o sobě to noční můra nebyla, protože se pracovalo s interface. Co už noční můra byla to byl marshalling. Jestli je u moderních VM nějaký pohodlnější mechanismus, to už nevím.

zdenek henek nereg.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #10 kdy: 18. 07. 2018, 10:53:40 »

Tohle ti udela maven nebo gradle automagicky, pokud potrebujes. Pluginy k tomu jsou, viz vyse.

(drobne varovani - ne nutne musi fungovat, pokud se do hry dostane Scala - https://www.scala-lang.org/old/sites/default/files/sids/dubochet/Mon,%202010-05-31,%2015:25/Storage%20of%20pickled%20Scala%20signatures%20in%20class%20files.pdf a pochopitelne pokud je ve hre nejaka reflexe je nutne byt obzvlast opatrny)

maven za me prejmenuje package - zmeni adresar, prejmenuje tridu  a pak to cele zase prelozi?

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #11 kdy: 18. 07. 2018, 11:01:08 »
Jo a pokud někoho zajímá, kde se to používá (spíše používalo) tak to byly systémy, kde se daly měnit zdrojové kódy za běhu. Kupříkladu Tomcat to možná dosud používá k tomu, aby uměl spustit novou verzi aplikace i bez restartu.
Tam ale nepracujete s oběma verzemi třídy v jedné metodě najednou. Tomcat prostě používá víc classloaderů, jak je to ve specifikaci Servletů.

Jestli je u moderních VM nějaký pohodlnější mechanismus, to už nevím.
Od Javy 9 k tomuhle slouží moduly ve spolupráci se ServiceLoader.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #12 kdy: 18. 07. 2018, 12:18:56 »

Tohle ti udela maven nebo gradle automagicky, pokud potrebujes. Pluginy k tomu jsou, viz vyse.

(drobne varovani - ne nutne musi fungovat, pokud se do hry dostane Scala - https://www.scala-lang.org/old/sites/default/files/sids/dubochet/Mon,%202010-05-31,%2015:25/Storage%20of%20pickled%20Scala%20signatures%20in%20class%20files.pdf a pochopitelne pokud je ve hre nejaka reflexe je nutne byt obzvlast opatrny)

maven za me prejmenuje package - zmeni adresar, prejmenuje tridu  a pak to cele zase prelozi?

Proc bys potreboval prejmenovat tu tridu?

Ghhh

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #13 kdy: 18. 07. 2018, 12:47:34 »

Tohle ti udela maven nebo gradle automagicky, pokud potrebujes. Pluginy k tomu jsou, viz vyse.

(drobne varovani - ne nutne musi fungovat, pokud se do hry dostane Scala - https://www.scala-lang.org/old/sites/default/files/sids/dubochet/Mon,%202010-05-31,%2015:25/Storage%20of%20pickled%20Scala%20signatures%20in%20class%20files.pdf a pochopitelne pokud je ve hre nejaka reflexe je nutne byt obzvlast opatrny)

maven za me prejmenuje package - zmeni adresar, prejmenuje tridu  a pak to cele zase prelozi?

Proc bys potreboval prejmenovat tu tridu?

Ondro, neptej se porad jak male dite :)

zdenek henek nereg.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #14 kdy: 18. 07. 2018, 14:39:52 »

Tohle ti udela maven nebo gradle automagicky, pokud potrebujes. Pluginy k tomu jsou, viz vyse.

(drobne varovani - ne nutne musi fungovat, pokud se do hry dostane Scala - https://www.scala-lang.org/old/sites/default/files/sids/dubochet/Mon,%202010-05-31,%2015:25/Storage%20of%20pickled%20Scala%20signatures%20in%20class%20files.pdf a pochopitelne pokud je ve hre nejaka reflexe je nutne byt obzvlast opatrny)

maven za me prejmenuje package - zmeni adresar, prejmenuje tridu  a pak to cele zase prelozi?

Proc bys potreboval prejmenovat tu tridu?

Pokud se maji obe pozivat v jedne tride, tak bych ji radeji mel pojmenovanou jinak.