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

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

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.

Rekneme, ze tohle je spis za bonusove body, potreba to neni...


BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #16 kdy: 18. 07. 2018, 17:17:08 »
Tohle je výhoda dynamických jazyků (Python, Javascript). Tam je ta třída first-class citizen.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #17 kdy: 19. 07. 2018, 00:48:07 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.

ava

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #18 kdy: 19. 07. 2018, 07:38:22 »
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.

Aha, OK, díky za opravu a vysvětlení.

Pro zajímavost, kdysi jsem dělal ve Smalltalku. Tam se zcela běžně dělají úpravy tříd za běhu, je ta to nejsamozřejmější věc na světě, protože celé IDE je vlastně napsané samo v sobě a běží samo v sobě a vyvíjí se tím, že to IDE v tom IDE člověk za běhu edituje. Může vám to připadat hrozné, ale v praxi je to neuvěřitelně praktické.

Změny tříd jsou v zásadě dvojí:

1) Buď se mění pouze metody (ať už třídní nebo instanční), to vlastně neznamená změnu třídy jako takové. Reference na instanci té třídy dále fungují, a nové metody jsou okamžitě k dispozici (takže mám třeba otevřené okno debuggeru, které mi otevřel failnutý assert v testu, dostepoval jsem se k podezřelé metodě, tak tu metodu hnedka upravím aniž bych debugger zavíral, zkusím z debuggeru zavolat metodu znova, funguje to, hotovo. Edit-compile-run je překonaný mýtus :-)

2) Upravím definici třídy, což v praxi skoro vždy znamená, že jsem přidal nebo ubral instanční proměnné. To už je problém, vzniká mi nová třída. Stane se to, že např. třída Foo se přejmenuje na ObsoleteFoo, existující reference na Foo teď ukazují na ObsoleteFoo, a vytváření nových instancí už dělá nová Foo-čka. Protože si s nejvyšší pravděpodobností Foo a ObsoleteFoo budou dost podobné, většinou nevadí, že v běžící vyvíjené aplikaci je někde Foo a někde ObsoleteFoo, a když chci mít jistotu, tak aplikaci pustím znovu...

Tohle všechno by v principu mohl hojně používat třeba Python nebo Ruby, to jsou jazyky které podle mě (na designové úrovni) nepřinášejí oproti Smalltalku nic navíc, jen spoustu věcí dělají hůře a pomaleji. U jazyků se statickými typy už by to bylo komplikovanější.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #19 kdy: 19. 07. 2018, 08:18:01 »
Pod JVM se také dělají změny tříd za běhu (třeba se takhle někdy řeší aspekty), pod JVM můžete spouštět i dynamické jazyky (Groovy, Jython). Možností je spoust a záleží na tom, čeho přesně chce tazatel docílit. Něco jiného je, pokud chce mít staticky typovaný kompilátorem kontrolovaný kód v Javě, a úplně něco jiného bude, pokud chce jen pracovat s objekty v JVM, které mají určité vlastnosti, a vůbec neřeší, jak se ten objekt v JVM vzal. Podle dotazu to vypadá spíš na první případ, ale s jistotou už se to asi nedozvíme, vzhledem k tomu, že andreaw.fean se zeptal, ale pak zjistil, že ho to vlastně nezajímá.


ava

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #20 kdy: 19. 07. 2018, 08:26:33 »
Pod JVM se také dělají změny tříd za běhu (třeba se takhle někdy řeší aspekty), pod JVM můžete spouštět i dynamické jazyky (Groovy, Jython). Možností je spoust a záleží na tom, čeho přesně chce tazatel docílit. Něco jiného je, pokud chce mít staticky typovaný kompilátorem kontrolovaný kód v Javě, a úplně něco jiného bude, pokud chce jen pracovat s objekty v JVM, které mají určité vlastnosti, a vůbec neřeší, jak se ten objekt v JVM vzal. Podle dotazu to vypadá spíš na první případ, ale s jistotou už se to asi nedozvíme, vzhledem k tomu, že andreaw.fean se zeptal, ale pak zjistil, že ho to vlastně nezajímá.

Jo, já v zásadě neprskám na JVM (i když některé věci co Smalltalkovské VM umí JVM neumí, třeba https://gbracha.blogspot.com/2009/07/miracle-of-become.html ), JVM mi přijde docela dobrá, spíš ty mainstreamové jazyky za moc nestojí :)

A. F.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #21 kdy: 19. 07. 2018, 19:52:54 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

zdenek henek nereg.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #22 kdy: 19. 07. 2018, 20:04:46 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

Xstream http://x-stream.github.io/
To je jedna z moznosti jak serializovat objekty do XML.

A. F.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #23 kdy: 19. 07. 2018, 20:07:22 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

Xstream http://x-stream.github.io/
To je jedna z moznosti jak serializovat objekty do XML.
Tak mě samozřejmě nešlo o tu serializaci do XML.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #24 kdy: 19. 07. 2018, 23:36:27 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

Xstream http://x-stream.github.io/
To je jedna z moznosti jak serializovat objekty do XML.
Tak mě samozřejmě nešlo o tu serializaci do XML.

Ale XML může sloužit např. v tom příkladě povýšení verze - nastartuju proces se starou verzí třídy a uložím do xml, pak nastartuju s novou verzí třídy a načtu. Pokud dokážu vyřešit nové nebo chybějící fieldy (nebo obecně změnu struktury), mám hotovo.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #25 kdy: 19. 07. 2018, 23:38:28 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

Představuju si to stejně jako je uvedeno zde (netestoval jsem):

https://stackoverflow.com/a/11759613/5950455

Tedy:

Kód: [Vybrat]
common.jar:
BaseInterface

v1.jar:
SomeImplementation implements BaseInterface

v2.jar:
OtherImplementation implements BaseInterface

command-line:
java -classpath common.jar YourMainClass
// you don't put v1 nor v2 into the parent classloader classpath

Then in your program:

loader1 = new URLClassLoader(new URL[] {new File("v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
loader2 = new URLClassLoader(new URL[] {new File("v2.jar").toURL()}, Thread.currentThread().getContextClassLoader());

Class<?> c1 = loader1.loadClass("com.abc.Hello");
Class<?> c2 = loader2.loadClass("com.abc.Hello");

BaseInterface i1 = (BaseInterface) c1.newInstance();
BaseInterface i2 = (BaseInterface) c2.newInstance();

Pokud by obě verze nesdíleli společné rozhraní BaseInterface, tak to tolik nevadí. Mohu je instancovat jako Object a potřebné metody (nebo přímo fieldy) si dohledat a použít pomocí reflexe:

Kód: [Vybrat]
import java.lang.reflect.*

public class Test {
   public String toString(){
      return "This is toString from Test!";
   }
}

Object   o = new Test();
Method m = o.getClass().getMethod("toString");
m.invoke(o);

Takovéhle pokusy se snadno testují v jshellu (v JDK od verze 9).

A. F.

Re:Dvě stejné třídy různých verzí (Java)
« Odpověď #26 kdy: 20. 07. 2018, 19:10:28 »
Nikdy jsem to nezkoušel, ale řekl bych, že pokud instancuju pomocí dvou různých classloaderů a reflexe, tak můžu získat docela snadno dvě instance totožné třídy ze dvou různých jarek, tedy ve dvou verzích. Pak záleží co s nimi chci dělat dál. Pomocí reflexe můžu dělat zase asi cokoli.

Použití si dokážu představit při potřebě přeuložit serializovaná data v jiné verzi třídy. Ale možná existuje na uvedený případ nějaký vhodnější kanonický postup. Ale častěji se stejně serializuje do nějakého neutrálního formátu, třeba xml, takže to není moc často potřeba.
Neměl by si nějaký odkaz? Potřebuji nasměrovat.

Představuju si to stejně jako je uvedeno zde (netestoval jsem):

https://stackoverflow.com/a/11759613/5950455

Tedy:

Kód: [Vybrat]
common.jar:
BaseInterface

v1.jar:
SomeImplementation implements BaseInterface

v2.jar:
OtherImplementation implements BaseInterface

command-line:
java -classpath common.jar YourMainClass
// you don't put v1 nor v2 into the parent classloader classpath

Then in your program:

loader1 = new URLClassLoader(new URL[] {new File("v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
loader2 = new URLClassLoader(new URL[] {new File("v2.jar").toURL()}, Thread.currentThread().getContextClassLoader());

Class<?> c1 = loader1.loadClass("com.abc.Hello");
Class<?> c2 = loader2.loadClass("com.abc.Hello");

BaseInterface i1 = (BaseInterface) c1.newInstance();
BaseInterface i2 = (BaseInterface) c2.newInstance();

Pokud by obě verze nesdíleli společné rozhraní BaseInterface, tak to tolik nevadí. Mohu je instancovat jako Object a potřebné metody (nebo přímo fieldy) si dohledat a použít pomocí reflexe:

Kód: [Vybrat]
import java.lang.reflect.*

public class Test {
   public String toString(){
      return "This is toString from Test!";
   }
}

Object   o = new Test();
Method m = o.getClass().getMethod("toString");
m.invoke(o);

Takovéhle pokusy se snadno testují v jshellu (v JDK od verze 9).

Excelentní. Takhle na talíři jsem to nečekal. Vyzkouším. Díky!