Jakému typu omylu zabrání to, že ty třídy nebudou na classpath? To si nějak neumím moc představit.
Omylu, že tu třídu použijete.
Doposud se vezme první třída dané signatury na classpath, ikdyž tam bude ve vícero verzí jar. Tzn. to chování která třída se vezme je deterministické.
No, deterministické… Pokud máte zaručené pořadí JARek na classpath, je to determenistické. Jenže pokud se classpath sestavuje dynamicky, třeba skriptem nebo hvězdičkou, je to sice deterministické, ale určit, jaké pořadí to v jakém případě bude, není úplně snadné.
Ale hlavně vám je úplně k ničemu, že aplikace deterministicky načte třídu z
c-1.0.jar, když knihovna potřebuje stejně pojmenovanou třídu z
c-2.0.jar.
Čím to dělá špatně Maven?
S Mavenem to nijak nesouvisí. Bavíme se tu o Java modulech (projekt Jigsaw).
Maven přece nemůže za to, že JRE nepodporuje načtení konkrétní verze importu.
Až do Javy 8 to skutečně podporované nebylo. Od Javy 9 to díky modulům podporované je.
Ano ale toto já právěže chápu, jenže to jde přece řešit podporou verzí u importů v bytecode a buiidovací nástroj jako maven by se postaral, aby tam ty správné verze do bytecode dal (aby se o to nemusel starat proramátor). Porotože Maven z pom.xml ví, že A závisí na C-1.0 a B na C-2.0, takže může na classpath vložit cosi, co podporuje JRE a podle čeho bude rozhodnuto, které C-X.0 se zrovna použije. Takže A bude při běhu volat z C-1.0 a b bude volat z C-2.0.
Tento teoretický nástroj, který jste vymyslel, a který má ještě určité mouchy, někdo vzal a v podobě projektu Jigsaw ho dotáhl do použitelné podoby. Takže dnes máme k dispozici Java moduly. Nebo-li to, co popisujete jako „dalo by se řešit“ je už právě pomocí modulů vyřešené.
Je tam v Mavenu ta část, co dokáže vyřešit tranzitivní závislosti, a o to přeci jde především.
Pokud jde o něco především, tak o to, aby tranzitivní závislosti nebyly zveřejněné. To, že nějaká knihovna A používá pro implementaci nějaké další knihovny B, nemá zajímat nikoho jiného než tu knihovnu A samotnou. Když knihovna A v příští verzi pro implementaci použije jinou knihovnu C, nemá to ovlivnit nikoho, kdo knihovnu A používá. A tohle řeší Maven špatně (dá vám tranzitivní závislosti na compiletime classpath), a za běhu to bez modulů ani nijak řešit nejde, protože když máte jen runtime classpath, ta knihovna B nebo C na ní musí být, a to ovlivňuje váš kód, který o B a C nemá vůbec nic vědět.
No takhle, vyvíjelo se tak posledních 20 let a ty projekty fungují. Můžete dát příklad, kdy konkrétně kvůli chybějícímu zapouzdření na úrovni modulů něco nefungovalo? Jako viděl jsem už pár velkých projektů a chybějící zapouzdřenost na úrovni modulů bylo to úplně nejposlednější, co by mi vadilo.
Když to nefungovalo, tak to samozřejmě není nikde v praxi použité. Nedávalo by smysl, aby někdo před dvaceti lety napsal kód, který začne fungovat, až někdo možná za dvacet let přidá do Javy moduly. Ale ty problémy reálně existují, akorát se různými způsoby obcházejí.
U větších projektů máte třeba na classpath spoustu tranzitivně dotažených pomocných knihoven a tříd. Takže tam máte třeba několik tříd
StringUtil(s), z nichž některé byly myšlené čistě jako interní třídy nějakých knihoven, a některé jsou opravdu myšlené jako utilitní třídy pro veřejné použití, ale pořád je máte do projektu zavlečené jen jako tranzitivní závislost. Typicky ale chcete používat jen jednu z nich z knihovny, která je pro daný projekt vybraná. Takže to musíte někde zdokumentovat, která třída to má být, a pokaždé, když jí chcete použít, musíte si na to dávat pozor, přičemž IDE vás zbytečně mate nabídkou tříd, které používat nemáte. Když použijete špatnou třídu, IDE ani kompilátor nijak neprotestují – a najednou máte v projektu závislost na další knihovně, zavlečenou omylem, v žádném pom.xml ani jinde není nadefinovaná. Přínos takového chování není žádný, má to jen negativní důsledky.
Konfliktu verzí závislostí předcházejí některé knihovny tak, že zdrojáky závislé knihovny přibalí do svého projektu a přesunou je do svého package. Takže takhle máte třeba ASM aCGlib přibalené ve Springu, v knihovně Jodd máte přibalené taky ASM…
Apache HTTP Components řešily zpětně nekompatibilní změny mezi verzemi 3 a 4 tak, že verze 4 má jiné package – tím pádem může jeden projekt záviset na verzích 3 i 4 a nepotluče se to.