# Jars in unterschiedlichen Versionen



## JavaMe (28. Feb 2012)

Hallo zusammen,

hier mal eine Frage zum Umgang mit Bibliotheken, die von Teilen einer Anwendung in unterschiedlichen Versionen verwendet werden:

Das Scenario:

Gegeben ist eine Webanwendung (nachfolgend Basisanwendung genannt), bestehend aus ein paar Java Servlets, die auf einem Tomcat Server zum Einsatz kommt (wobei das Ganze auch auf eine Java Standalone Anwendung bezogen werden kann). Diese bedient sich ca. 60 Fremdbibliotheken, die unter WEB-INF\lib (oder einfach im Classpath) liegen. Darunter befinden sich Jars aus diversen Frameworks (Spring, Log4j), Jars aus dem Apache Commons Projekt, Jars für IBMs Websphere MQ (MQ classes for Java),usw. 

Jetzt muss diese Basisanwendung erweitert werden, wozu ein Third-Party Framework (nachfolgend "TP-Framework" genannt) eingesetzt werden muss, welches ebenfalls eine Menge an Fremdbibliotheken (71 Jars) mitbringt.

Das Problem hierbei: 

Basisanwendung und das TP-Framework nutzen gleiche Bibliotheken, wobei diese sich teilweise in den Versionen unterscheiden.

Hier mal ein paar Beispiele:

Basisanwendung <=> TP-Framework
=============================================
com.ibm.mq-6.0.2.5.jar <=> com.ibm.mq-6.0.2.0.jar
connector-1.0.1.jar <=> connector-1.0.jar
dom4j-1.6.1.jar <=> dom4j-1.5.2.jar
slf4j-api-1.6.1.jar	 <=> slf4j-api-1.5.6.jar
xalan-2.7.1.jar <=> xalan-2.7.0.jar
xercesImpl-2.10.0.jar <=> xercesImpl-2.8.1.jar
xmlsec-1.4.3.jar <=> xmlsec-1.4.5.jar

Die Frage hierbei:

Wie kriege ich dieses Wirrwarr der doppelten Jars in unterschiedlichen Versionen in den Griff und wie vermeide ich Probleme, wenn die Klassen dieser Jars nicht kompatibel sind oder es Unterschiede in der Implementierung gibt ?

Wir haben dieses Problem bereits in einem Projekt leidvoll erfahren müssen, als wir bei Verwendung einer "falschen" (andere JAR Version, die sich lediglich im Minor Code unterschied!!!) XML-Parser Bibliothek ein fehlerhaftes Verhalten in der betroffenen Anwendung bekamen. Die Analyse hat damals elendig viel Zeit gekostet und trat natürlich nur beim Kunden auf.

Ich sehe zwei Lösungsmöglichkeiten:

1) Ich behalte die Bibliotheken der Basisanwendung und schmeiße die Fremdbibliotheken des TP-Frameworks raus, bzw. stelle Sie nicht in den Classpath der Anwendung (bzw. in das WEB-INF/lib Verzeichnis der Webanwendung). Dann bete ich, dass das TP-Fw funktioniert und das auch bei zukünftigen Änderungen so bleibt. 
Vorteil: Ich kann das Fw direkt in die Basisanwendung einbinden, habe es also sehr einfach.
Nachteil: Das Fw funktioniert nicht, weil es Probleme mit den Jars der Basisanwendung kriegt.

2) Ich verlagere das TP-Fw in eine neue Webanwendung, um dieses mit den Original Fremdbibliotheken aus der Auslieferung zu nutzen und stelle darin die in der Basisanwendung benötigten Funktionen des TP-Frameworks per Servlet zur Verfügung.
Vorteil: Kompatibilitätsprobleme kann es nicht geben, da Basisanwendung und das Fw die "eigenen" Fremdbibliotheken verwenden.
Nachteil: Overhead bei der Entwicklung (deutlich höherer Aufwand) und beim Betrieb (da teilweise sehr große XML Nachrichten von einer zur anderen Anwendung zu übertragen sind).

Keine der Lösungen scheint mir ideal zu sein.

Kennt noch jemand eine dritte Lösung oder kann mir zu einer der aufgezeigten Lösungen raten (vlt. weil ich mir bei den aufgezeigten Bibliotheken über derlei Probleme keine Sorgen machen muss) ?

Bin gespannt, ob sich jemand meines Themas annimmt und sich irgendwelche Java "Profis" melden, die derlei Probleme vlt. schon gelöst haben.

Viele Grüße und Danke vorab für jede Hilfe

Holger


----------



## nillehammer (28. Feb 2012)

> Wie kriege ich dieses Wirrwarr der doppelten Jars in unterschiedlichen Versionen in den Griff und wie vermeide ich Probleme, wenn die Klassen dieser Jars nicht kompatibel sind oder es Unterschiede in der Implementierung gibt ?


Das ist in der Tat ein Problem, wenn es konfliktierende Dependencies gibt. I.d.R. sind aber bei den ganzen Bibliotheken die Versionen mit gleichem Major-/Minor-Release zueinander kompatibel. Wenn Du also bspw. folgenden Konflikt hast: com.ibm.mq-6.0.2.5.jar <=> com.ibm.mq-6.0.2.0.jar dann nimm das neuere (hier also 6.0.2.5) Das haut in der Regel hin.

Sowas hier ist dann schon problematischer: dom4j-1.6.1.jar <=> dom4j-1.5.2.jar. Da kann man nur hoffen, dass dom4j in dem 1.6er Zweig wenigstens weiterhin das public API von 1.5 unterstützt. Sonst kommt man aus der Nummer fast nicht mehr raus


----------



## JavaMe (28. Feb 2012)

Danke für die Antwort 

Hierbei

dom4j-1.6.1.jar <=> dom4j-1.5.2.jar.

habe ich bewusst "übertrieben".

In Wirklichkeit sind die beiden Jars nämlich identisch  Wollte es aber bewusst auf die Spitze treiben. Bei allen anderen Beispielen sind die Versionen aber tatsächlich unterschiedlich.

Deine Aussage

"die Versionen mit gleichem Major-/Minor-Release zueinander kompatibel"

beruhigt mich schon einmal und bestärkt mich in dem Vorhaben, Lösung 1 zu nehmen.

Was hältst Du denn von Lösung 2 ?


----------



## Airborne (28. Feb 2012)

auf jeden Fall solltest du das gerade ziehen - in die eine oder andere Richtung. 
Wie konnte es denn zu diesem Schiefstand gekommen? 

60 libs sind auch recht viel, da ist bestimmt einiges nicht mehr genutzt.


----------



## maki (28. Feb 2012)

Maven, ein Buildtool mit Dependencymanagement versucht dieses Wirrwar etwas zu ordnen, kann natürlich auch nicht zaubern wenn sich die API bzw. Implementierungen zu stark unterscheiden.
OSGi kann zaubern und löst dieses Problem zuverlässig, da dort mehrere Versionen einer Jar gleichzeitig verfügbar sein können, setzt aber eben ein OSGI Environment voraus.

60 Jars für einen eingermassen umfangreiche WebApp finde ich eprsönlich nicht z uungewöhnlcih, Hibernate, JSF (zumindest früher), etc.  häufen gerne mal viele Jars an.


----------



## JavaMe (28. Feb 2012)

Airborne hat gesagt.:


> auf jeden Fall solltest du das gerade ziehen - in die eine oder andere Richtung.
> Wie konnte es denn zu diesem Schiefstand gekommen?
> 
> 60 libs sind auch recht viel, da ist bestimmt einiges nicht mehr genutzt.



Das liegt daran, dass wir in die bestehende und sehr komplexe Webanwendung ein zusätzliches, ebenfalls sehr komplexes, Dritthersteller Framework integrieren müssen, um neue Funktionen zu implementieren. 

Natürlich ist die Anzahl der Jars sehr hoch. Aber -wie mein Vorredner schon schreibt- nicht ungewöhnlich. Zur Zeit lasse ich vom Hersteller des zu integrierenden Frameworks untersuchen, welche JARs wir für unsere Zwecke wirklich benötigen. Hier habe ich die stille Hoffnung, dass da ein dicker Brocken herausfällt.


----------



## JavaMe (28. Feb 2012)

maki hat gesagt.:


> Maven, ein Buildtool mit Dependencymanagement versucht dieses Wirrwar etwas zu ordnen, kann natürlich auch nicht zaubern wenn sich die API bzw. Implementierungen zu stark unterscheiden.
> OSGi kann zaubern und löst dieses Problem zuverlässig, da dort mehrere Versionen einer Jar gleichzeitig verfügbar sein können, setzt aber eben ein OSGI Environment voraus.



Das Buildtool "Maven" muss ich mir wohl mal näher ansehen. Habe es bereits in einem anderen Thread, in dem ich nach einem Tool zur Erkennung von Klassen Duplikaten in JARS gefragt habe, empfohlen bekommen. Bei uns kommt zwar ANT als Buildtool zum Einsatz. Aber ich würde es einfach nur für die Dependencyanalyse nutzen.

OSGi scheint mir dann doch eine Hausnummer zu groß zu sein. So etwas kriege ich weder bei uns noch beim Kunden eingesetzt.


----------



## maki (28. Feb 2012)

> Aber ich würde es einfach nur für die Dependencyanalyse nutzen.


"Ich will Maven einfach nur für ... nutzen" sind die Worte, mit denen jedes Drama beginnt, in dessen letztem Akt Maven als Ausgeburt der Hölle verdammt wird *g*

Um eines klarzustellen: Ich bin absoluter Maven Fan! 

Aber Maven würde entweder "alles" machen, oder gar nicht eingesetzt werden.

Maven ist absolut unflexibel (und das ist imho gut so), man passt Maven nicht an das Projekt an, sondern das Projekt an Maven (und sich selber am besten auch gleich), sonst wird das nix.


----------



## JavaMe (28. Feb 2012)

@maki:

Das sehe ich anders:

Ich brauche ja ein Tool, mit dem ich Duplikate von Klassen in mehreren Jars ausfindig machen kann, um abschätzen zu können, ob ich in Probleme reinlaufe und welche JARs ich der Anwendung mitgeben muss.

Eine solche Untersuchung muss ich in unserem Projekt nur einmalig und nicht bei jedem Build durchführen! Ich gebe Dir Recht, dass ansonsten ein Mischmasch aus ANT und Maven nicht empfehlenswert ist.

Ergo würde ich jetzt EINMALIG ein simples Projekt erstellen, in welches ich sämtliche Jars reinschmeiße und mit diesem Maven-Plugin https://github.com/ning/maven-duplicate-finder-plugin auf doppelt vorhandene Klassen untersuchen lasse.

Ich denke, dass das hinzubekommen ist, oder ? 

Vlt. vertue ich mich auch. Dann werde ich sicherlich an Deinen Rat zurückdenken ;-)


----------



## maki (28. Feb 2012)

Wenn du fragen immer her damit 

Wollte dir aber keine falsche Hoffnung machen (ist alles ganz einfach.. blabla), musst eigentlich “nur“ dein projekt nach maven konventionen umbauen.


----------



## ProChris (29. Feb 2012)

Hallo,

möchte man zwei Jars in unterschiedlichen Versionen verwenden, so kommt es zu einem Namespace Konflikt. Es gibt diverse Lösungsansätze den Namespace Konflikt zu lösen:

1. Man könnte die Jars aus Deinem Framework einem Refactoring unterziehen. Konkret bedeutet das Du jede Klasse in dem Framework ein Präfix vor dem Package Namen setzt. Zum Beispiel kann aus org.example... dann com.yourcompany.org.example... gemacht werden. Bei diesem Lösungsansatz ist zu klassifizieren, ob Aufwand und nutzen wirklich im Verhältnis steht. (Ich bevorzuge diese Variante nicht. Sie ist eher für kleinere Projekte tragbar)

2. Verantwortlich für das Namespace Problem ist der Classloader, denn dieser kann keine qualifizierte Aussage darüber treffen, welche Klasse "zuerst" geladen werden soll, wenn beide gleich benannt sind und den gleichen Package Pfad aufweisen. Hier wäre ein möglicher Lösungsansatz, eine Webapplikation zu implementieren, denn diese hat ihren eigenen Classpath. Wie bereits erwähnt bietet Maven eine hervorragende Möglichkeit Webapplikationen zu generieren. Nach dem Buildprozess sollte dann im Ergebnis eine war Datei entstanden sein. Diese kann beispielsweise auf einem Tomcat deployed werden. Aus meiner Sicht wäre dieses die bevorzugte Variante.

Viele Grüße

ProChris


----------



## bygones (29. Feb 2012)

maki hat gesagt.:


> Wollte dir aber keine falsche Hoffnung machen (ist alles ganz einfach.. blabla), musst eigentlich *“nur“* dein projekt nach maven konventionen umbauen.


aus Erfahrung mit dem "nur" musste ich ueber das Wort lachen


----------



## JavaMe (29. Feb 2012)

Hallo ProChris,

nachdem ich mir ein Tool geschrieben habe, welches in den weit über 100 Jars beider Komponenten (Basisanwendung und Fw) mehrfach vorkommende Klassen aufspürt und mir die betroffenen JARs am Ende auflistet, bin ich inzwischen auch soweit, eine zusätzliche Webanwendung zu entwickeln, um jeder Komponente seinen eigenen Classpath und damit auch seine eigenen JARs geben zu können.

Bei der Analyse ist nämlich folgendes Ergebnis rausgekommen:

Jar1 / Jar2 / Jar3 => Anz Klassen, die mehrfach vorkommen
================================================
resolver.jar / xml-resolver-1.2.jar => 30
geronimo-jta_1.1_spec-1.1.jar / jta-1.1.jar => 18
jaxen-1.1.1.jar / xml-apis.jar / xmlbeans-2.3.0.jar => 1
axis2-kernel-1.5.4.jar / axis2-transport-http-1.5.4.jar => 9
commons-lang-2.5.jar / velocity-1.7-dep.jar => 125
xmlsec-1.4.3.jar / xmlsec-1.4.5.jar => 344
slf4j-api-1.5.6.jar / slf4j-api-1.6.1.jar => 20
connector-1.0.jar / connector.jar => 37
velocity-1.7-dep.jar / velocity-1.7.jar => 270
stax-api-1.0-2.jar / xml-apis.jar => 1
xalan-2.7.0.jar / xalan.jar => 1112
commons-collections-3.1.jar / velocity-1.7-dep.jar => 34
activation-1.1.jar / geronimo-activation_1.1_spec-1.0.2.jar => 17
com.ibm.mq-6.0.2.0.jar / com.ibm.mq.jar => 140
xercesImpl-2.8.1.jar / xercesImpl.jar => 874
woden-impl-dom-1.0M8.jar / xml-apis.jar => 1
geronimo-javamail_1.4_spec-1.6.jar / mailapi.jar => 107
serializer.jar / xalan-2.7.0.jar => 89
geronimo-stax-api_1.0_spec-1.0.1.jar / stax-api-1.0-2.jar / xml-apis.jar => 33
xml-apis.jar / xmlbeans-2.3.0.jar => 3

Das ist mir ehrlich gesagt zu umfangreich und in meinen Augen nicht mehr handlebar.

Ein Refacoring von Fremdbibliotheken kommt bei über 50 betroffenen JARs nicht in Frage. Die sollen unverändert bleiben.

Danke für Deinen Ratschlag!


----------



## mvitz (29. Feb 2012)

Naja, ein paar davon könnte man wohl ohne weiteres streichen (z.B. velocity-dep / eine der beiden JTA JARs), aber um alle Probleme zu lösen wird man wohl einigen Testaufwand betreiben müssen.


----------



## ProChris (29. Feb 2012)

Hallo JavaME,

ich helfe doch immer gern. Es gibt dafür so einen "Danke" Button ;-) den man betätigen kann. Nein Spass bei Seite.
Es ist nicht nur nicht mehr handhabbar, sondern macht das Updaten einzelner JAR nahezu unmöglich. Immer dann die Package Struktur anpassen zu müssen macht wirklich keinen Sinn.

Viele Grüße

ProChris


----------

