Skąd mam wiedzieć, która wersja kompilatora Java została użyta do zbudowania jar? Mam plik jar i mógł on zostać zbudowany w jednym z trzech JDK. Musimy dokładnie wiedzieć, który z nich, abyśmy mogli poświadczyć zgodność. Czy wersja kompilatora jest osadzona gdzieś w plikach klasy lub jar?
212
Created-By: 1.7.0_13 (Oracle Corporation)
Created-By: Apache Maven
iBuild-Jdk: 1.8.0_25
Odpowiedzi:
Nie można tego stwierdzić na podstawie samego pliku JAR.
Pobierz edytor szesnastkowy i otwórz jeden z plików klas w pliku JAR i spójrz na przesunięcia bajtów od 4 do 7. Informacje o wersji są wbudowane.
http://en.wikipedia.org/wiki/Java_class_file
Uwaga: jak wspomniano w komentarzu poniżej,
źródło
A
jar
to tylko pojemnik. Jest to archiwum plików latar
. Chociażjar
może zawierać interesujące informacje zawarte w hierarchii META-INF , nie ma obowiązku określania rocznika klas w swojej treści. W tym celu należy sprawdzić zawarte wclass
nim pliki.Jak wspomniał Peter Lawrey w komentarzu do pierwotnego pytania, niekoniecznie musisz wiedzieć, która wersja JDK zbudowała dany
class
plik, ale możesz znaleźć wersję klasy bajtowejclass
pliku zawartego w plikujar
.Tak, to trochę do bani, ale pierwszym krokiem jest wyodrębnienie jednej lub więcej klas z
jar
. Na przykład:W systemie Linux, Mac OS X lub Windows z zainstalowanym Cygwin polecenie file (1) zna wersję klasy.
Lub alternatywnie, używając
javap
z JDK jako @ jikes.thunderbolt trafnie wskazuje:A jeśli zostaniesz przeniesiony do
Windows
środowiska bez jednegofile
lubgrep
FWIW, zgodzę się, że
javap
powie o wiele więcej o danymclass
pliku niż pierwotne pytanie.W każdym razie inna wersja klasy, na przykład:
Numer główny wersji klasy odpowiada następującym wersjom JDK Java:
źródło
file
nie wykazały, ale udało mi się ręcznie sprawdzić klasę z tym poleceniem:hexdump ~/bin/classes/P.class | head
. Wystarczy spojrzeć na ósmy bajt i przekonwertować na dziesiętny.JAR=something.jar ; unzip -p $JAR `unzip -l $JAR | grep '\.class$' | head -1` | file -
file file.class
(5.22-1) początkowo nie pokazywał docelowego celu klasy Java: „file.class: [architecture = 6909806] [architecture = 6845039]”. Jednakfile -k file.class
zrobił to: „file.class: [architektura = 6909806] [architektura = 6845039] skompilował dane klasy Java, wersja 50.0 (Java 1.6)”. Wygląda na to, żefile
dostał tylko pierwszy mecz w swojej bazie danych magicfiles bez-k
.Oto sposób, w jaki Java może znaleźć te informacje.
Windows:
javap -v <class> | findstr major
Unix:
javap -v <class> | grep major
Na przykład:
> javap -v Application | findstr major major version: 51
źródło
<class>
parametr?Application.class
plik i okazało się, że został skompilowany dla Java 7 (major version: 51
).javac
wersję, która skompilowała pliki .class, o co proszono.Nie ma potrzeby rozpakowywania pliku JAR (jeśli jedna z nazw klas jest znana lub jest sprawdzana, np. Za pomocą 7zip), więc w systemie Windows wystarczające byłyby:
źródło
javac
wersję, która skompilowała pliki .class, o co proszono.Kompilator Java (
javac
) nie buduje słoików, tłumaczy pliki Java na pliki klas. Narzędzie Jar (jar
) tworzy rzeczywiste słoiki. Jeśli nie określono żadnego niestandardowego manifestu, domyślny manifest określa, która wersja JDK została użyta do utworzenia jar.źródło
Ponieważ musiałem przeanalizować grube słoiki, byłem zainteresowany wersją każdej klasy w pliku jar. Dlatego podjąłem podejście Joe Liversedge https://stackoverflow.com/a/27877215/1497139 i połączyłem je z https://stackoverflow.com/a/3313839/1497139 tabelą wersji klas klasy Davida J. Liszewskiego, aby utworzyć skrypt bash jarv, aby wyświetlić wersje wszystkich plików klas w pliku jar.
stosowanie
Przykład
Skrypt Bash jarv
źródło
head -1
może być używany w połączeniu ze skryptem: zwykle wystarczy zobaczyć wersję pierwszej klasy w pliku jar.wersję kompilatora Java można znaleźć w plikach .class za pomocą edytora heksadecymalnego.
Krok 1: Wyodrębnij pliki .class z pliku jar za pomocą ekstraktora zip
krok 2: otwórz plik .class w edytorze szesnastkowym. (Użyłem wtyczki edytora szesnastkowego notatnika ++. Ta wtyczka odczytuje plik jako plik binarny i pokazuje go w postaci szesnastkowej). Możesz zobaczyć poniżej.
Indeks 6 i 7 podaje główny numer wersji używanego formatu pliku klasy. https://en.wikipedia.org/wiki/Java_class_file
Java SE 11 = 55 (0x37 hex)
Java SE 10 = 54 (0x36 hex)
Java SE 9 = 53 (0x35 hex)
Java SE 8 = 52 (0x34 hex),
Java SE 7 = 51 (0x33 hex),
Java SE 6.0 = 50 (0x32 hex),
Java SE 5.0 = 49 (0x31 hex),
JDK 1.4 = 48 (0x30 hex),
JDK 1.3 = 47 (0x2F hex),
JDK 1.2 = 46 (0x2E hex),
JDK 1.1 = 45 (0x2D hex).
źródło
Możesz poznać wersję binarną Java, sprawdzając pierwsze 8 bajtów (lub używając aplikacji, która potrafi).
Sam kompilator, zgodnie z moją najlepszą wiedzą, nie wstawia żadnego podpisu identyfikującego. I tak nie widzę czegoś takiego w formacie klasy specyfikacji pliku VM .
źródło
javac
wersję, która skompilowała pliki .class, o co proszono.Kod wysłane przez Owena można powiedzieć informacje wymienione przez szereg innych odpowiedzi tutaj:
Zobacz także tę i tę stronę. Skończyło się na szybkim modyfikowaniu kodu produktów umysłowych, aby sprawdzić, do czego została skompilowana każda z moich zależności.
źródło
javac
wersję, która skompilowała pliki .class, o co proszono.Programiści i administratorzy używający Bash mogą uznać te funkcje wygody za pomocne:
Możesz je wkleić do jednorazowego użytku lub dodać do
~/.bash_aliases
lub~/.bashrc
. Wyniki wyglądają mniej więcej tak:i
EDYCJA Jak wskazuje jackrabbit , nie możesz w 100% polegać na manifeście, aby powiedzieć ci coś pożytecznego. Jeśli tak, to możesz wyciągnąć go w swojej ulubionej powłoce UNIX za pomocą
unzip
:Ten .jar nie ma nic użytecznego w manifeście na temat zawartych klas.
źródło
javac
wersję, która skompilowała pliki .class, o co proszono.Jeden liner (Linux)
unzip -p mylib.jar META-INF/MANIFEST.MF
Spowoduje to wydrukowanie zawartości
MANIFEST.MF
pliku na standardowe wyjście (mam nadzieję, że plik znajduje się w pliku jar :)W zależności od tego, co zbudowało twój pakiet, znajdziesz wersję JDK w
Created-By
lubBuild-Jdk
key.źródło
MANIFEST.MF
, a także nie ma obowiązku poprawności wartości (Tak, kiedyś spotkałem się.jar
z fałszywą wartością).javac
wersję, która skompilowała pliki .class, o co proszono.Każdy plik klasy ma numer wersji osadzony na poziomie kodu bajtowego, którego JVM używa, aby sprawdzić, czy podoba mu się ten konkretny fragment kodu bajtowego, czy nie. To 48 dla Java 1.4, 49 dla Java 1.5 i 50 dla Java 6.
Istnieje wiele kompilatorów, które mogą generować kod bajtowy na każdym poziomie, javac używa opcji „-target”, aby wskazać, który poziom kodu bajtowego ma zostać wygenerowany, a javac Java 6 może generować kod bajtowy dla przynajmniej 1.4, 1.5 i 6. Nie wierzę, że kompilator wstawia wszystko, co może zidentyfikować sam kompilator, i myślę, że o to prosisz. Coraz częściej stosuje się także kompilator Eclipse, ponieważ jest to pojedynczy słoik, który może działać tylko z JRE.
W pliku jar znajduje się zwykle wiele klas, a każda z nich jest niezależna, dlatego musisz sprawdzić wszystkie klasy w słoiku, aby mieć pewność co do właściwości zawartości.
źródło
W odpowiedzi na odpowiedź Davida J. Liszewskiego uruchomiłem następujące polecenia, aby wyodrębnić manifest pliku jar na Ubuntu:
źródło
unzip -p LiceneSearch.jar META-INF/MANIFEST.MF
javac
wersję, która skompilowała pliki .class, o co proszono.Wiele razy możesz patrzeć na całe pliki jar lub pliki wojenne zawierające wiele plików jar oprócz siebie.
Ponieważ nie chciałem ręcznie sprawdzać każdej klasy, napisałem program Java, aby to zrobić:
https://github.com/Nthalk/WhatJDK
Chociaż nie mówi to o tym, z czym klasa została skompilowana, określa, jakie JDK będą mogły ZAŁADOWAĆ klasy, co prawdopodobnie jest tym, od czego chciałeś zacząć.
źródło
Aby rozwinąć odpowiedzi Jonathona Fausta i McDowell : Jeśli korzystasz z systemu opartego na * nix, możesz użyć
od
(jednego z pierwszych programów uniksowych 1, który powinien być dostępny praktycznie wszędzie), aby wysłać zapytanie do.class
pliku na poziomie binarnym:Spowoduje to wyświetlenie znanych wartości całkowitych, np.
50
ForJava 5
,51
forJava 6
i tak dalej.1 Cytat z https://en.wikipedia.org/wiki/Od_(Unix)
źródło
javac
wersję, która skompilowała pliki .class, o co proszono.Napisałem również własny skrypt bash, aby zrzucić wersję Java wymaganą przez wszystkie słoiki przekazane w wierszu poleceń ... Mój jest trochę szorstki, ale dla mnie działa ;-)
przykładowe użycie
jar_dump_version_of_jvm_required.sh
źródło
Możesz to łatwo zrobić w wierszu poleceń, wykonując następujący proces:
Jeśli znasz dowolną nazwę klasy w słoiku, możesz użyć następującego polecenia:
przykład:
Wynik :
Krótki przegląd:
źródło
Sprawdzasz w pliku manifestu przykład słoika:
Wersja manifestu: 1.0 Utworzono: 1.6.0 (IBM Corporation)
źródło
W systemie Windows wykonaj następujące czynności:
Teraz Eclipse wyświetli dokładną wersję główną i dodatkową.
źródło
Buduję mały skrypt bash (na github) w oparciu o sugestię Davidsa za pomocą
file
poleceniaźródło