Какая версия javac построила мою банку?

Как я могу определить, какая версия компилятора Java была использована для сборки банку? У меня есть файл jar, и он мог быть построен в любом из трех JDK. Нам нужно точно знать, какой из них, поэтому мы можем подтвердить совместимость. Является ли версия компилятора встроенной в файлы classов или jar?

Вы не можете сказать из самого файла JAR, обязательно.

Загрузите шестнадцатеричный редактор и откройте один из файлов classов внутри JAR и посмотрите на байтовые смещения с 4 по 7. Введена информация о версии.

http://en.wikipedia.org/wiki/Java_class_file

Примечание. Как упоминалось в комментарии ниже,

эти байты говорят вам, какая версия компиляции classа FOR, а не какая версия скомпилировала ее.

jar – это просто контейнер. Это файловый архив ā la tar . Хотя в jar может содержаться интересная информация, содержащаяся в ее иерархии META-INF , она не обязана указывать урожайность classов в ее содержимом. Для этого нужно изучить файлы class .

Как уже упоминал Питер Лори в комментарии к первому вопросу, вы не можете знать, какой выпуск JDK создал данный файл class , но вы можете узнать версию classа байтового кода файла class содержащуюся в jar .

Да, этот вид отстой, но первым шагом является извлечение одного или нескольких classов из jar . Например:

 $ jar xf log4j-1.2.15.jar 

В Linux, Mac OS X или Windows с установленной Cygwin команда file (1) знает версию classа.

 $ file ./org/apache/log4j/Appender.class ./org/apache/log4j/Appender.class: compiled Java class data, version 45.3 

Или, альтернативно, использование javap из JDK как @ jikes.thunderbolt метко указывает:

 $ javap -v ./org/apache/log4j/Appender.class | grep major major version: 45 

И если вы отнесены к среде Windows без file или grep

 > javap -v ./org/apache/log4j/Appender.class | findstr major major version: 45 

FWIW, я соглашусь, что javap будет рассказывать намного больше о заданном файле class чем заданный исходный вопрос.

В любом случае, другая версия classа, например:

 $ file ~/bin/classes/P.class /home/dave/bin/classes/P.class: compiled Java class data, version 50.0 

Основная версия версии classа соответствует следующим версиям Java JDK:

  • 45.3 = Java 1.1
  • 46 = Java 1.2
  • 47 = Java 1.3
  • 48 = Java 1.4
  • 49 = Java 5
  • 50 = Java 6
  • 51 = Java 7
  • 52 = Java 8
  • 53 = Java 9

Вот способ Java, чтобы найти эту информацию.

Windows: javap -v | findstr major javap -v | findstr major
Unix: javap -v | grep major javap -v | grep major

Например:
> javap -v Application | findstr major major version: 51

Компилятор Java ( javac ) не создает банки, он переводит файлы Java в файлы classов. Инструмент Jar ( jar ) создает реальные банки. Если пользовательский манифест не указан, в манифесте по умолчанию указывается, какая версия JDK использовалась для создания баннера.

Нет необходимости распаковывать JAR (если одно из имен classов известно или просматривается, например, с использованием 7zip), поэтому в Windows будет достаточно:

 javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major 

Вы можете указать двоичную версию Java, проверив первые 8 байтов (или используя приложение, которое может).

Сам компилятор, насколько мне известно, не вставляет никакой идентифицирующей сигнатуры. В любом случае я не могу разглядеть такую ​​вещь в формате classа спецификации VM .

Код, отправленный Owen, может сообщить вам информацию, указанную рядом других ответов здесь:

 public void simpleExample () { FileInputStream fis = new FileInputStream ("mytest.class"); parseJavaClassFile ( fis ); } protected void parseJavaClassFile ( InputStream classByteStream ) throws Exception { DataInputStream dataInputStream = new DataInputStream ( classByteStream ); magicNumber = dataInputStream.readInt(); if ( magicNumber == 0xCAFEBABE ) { int minorVer = dataInputStream.readUnsignedShort(); int majorVer = dataInputStream.readUnsignedShort(); // do something here with major & minor numbers } } 

См. Также этот и этот сайт. Я быстро модифицировал код Mind Products, чтобы проверить, для чего были скомпилированы каждая из моих зависимостей.

Один лайнер (Linux)

unzip -p mylib.jar META-INF/MANIFEST.MF

Это печатает содержимое файла MANIFEST.MF в stdout (надеюсь, что в вашем файле jar есть один файл 🙂

В зависимости от того, что построил ваш пакет, вы найдете версию JDK в Build-Jdk Created-By Build-Jdk или « Build-Jdk .

Каждый файл classа имеет номер версии, встроенный для уровня байтового кода, который JVM использует, чтобы увидеть, нравится ли ему этот конкретный кусок байтового кода или нет. Это 48 для Java 1.4, 49 для Java 1.5 и 50 для Java 6.

Существует множество компиляторов, которые могут генерировать байтовый код на каждом уровне, javac использует параметр «-target», чтобы указать, какой уровень байтового кода для генерации, а Java 6 javac может генерировать байтовый код, по меньшей мере, 1,4, 1,5 и 6. Я не что компилятор вставляет все, что может идентифицировать сам компилятор, о чем я думаю, что вы просите. Кроме того, все чаще используется компилятор Eclipse, поскольку он представляет собой единую банку, которая может работать только с JRE.

В файле jar обычно бывает много classов, и каждый из них независим, поэтому вам нужно исследовать все classы в банке, чтобы быть уверенными в характеристиках содержимого.

Разработчики и администраторы, работающие с Bash, могут найти полезные функции:

 jar_jdk_version() { [[ -n "$1" && -x "`command -v javap`" ]] && javap -classpath "$1" -verbose $(jar -tf "$1" | grep '.class' | head -n1 | sed -e 's/\.class$//') | grep 'major version' | sed -e 's/[^0-9]\{1,\}//' } print_jar_jdk_version() { local version version=$(jar_jdk_version "$1") case $version in 49) version=1.5;; 50) version=1.6;; 51) version=1.7;; 52) version=1.8;; esac [[ -n "$version" ]] && echo "`basename "$1"` contains classes compiled with JDK version $version." } 

Вы можете вставлять их для одноразового использования или добавлять их в ~/.bash_aliases или ~/.bashrc . Результаты выглядят примерно так:

 $ jar_jdk_version poi-ooxml-3.5-FINAL.jar 49 

а также

 $ print_jar_jdk_version poi-ooxml-3.5-FINAL.jar poi-ooxml-3.5-FINAL.jar contains classes compiled with JDK version 1.5. 

РЕДАКТИРОВАТЬ Как отмечает г-н Джебрабиб , вы не можете на 100% полагаться на манифест, чтобы сообщить вам что-нибудь полезное. Если бы это было так, то вы могли бы вытащить его в своей любимой оболочке UNIX с помощью unzip :

 $ unzip -pa poi-ooxml-3.5-FINAL.jar META-INF/MANIFEST.MF Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 11.3-b02 (Sun Microsystems Inc.) Built-By: yegor Specification-Title: Apache POI Specification-Version: 3.5-FINAL-20090928 Specification-Vendor: Apache Implementation-Title: Apache POI Implementation-Version: 3.5-FINAL-20090928 Implementation-Vendor: Apache 

Этот .jar не имеет ничего полезного в манифесте об содержащихся classах.

Следуя ответу @David J. Liszewski, я выполнил следующие команды, чтобы извлечь манифест файла jar на Ubuntu:

 # Determine the manifest file name: $ jar tf LuceneSearch.jar | grep -i manifest META-INF/MANIFEST.MF # Extract the file: $ sudo jar xf LuceneSearch.jar META-INF/MANIFEST.MF # Print the file's contents: $ more META-INF/MANIFEST.MF Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.2 Created-By: 1.7.0_25-b30 (Oracle Corporation) Main-Class: org.wikimedia.lsearch.config.StartupManager 

Много раз вы могли бы смотреть на все файлы jar или военные файлы, которые содержат много файлов jar в дополнение к себе.

Поскольку я не хотел проверять каждый class, я написал java-программу для этого:

https://github.com/Nthalk/WhatJDK

 ./whatjdk some.war some.war:WEB-INF/lib/xml-apis-1.4.01.jar contains classes compatible with Java1.1 some.war contains classes compatible with Java1.6 

Хотя это не говорит, что class был скомпилирован WITH, он определяет, какие JDK смогут загружать classы, что, вероятно, вы и хотели начать.

Чтобы расширить ответы Джонатана Фауста и Макдауэлла : если вы используете систему на основе nix, вы можете использовать od (одну из самых ранних программ Unix 1, которая должна быть доступна практически везде) для запроса файла .class на двоичном уровне:

 od -An -j7 -N1 -t dC SomeClassFile.class 

Это приведет к получению знакомых целочисленных значений, например 50 для Java 5 , 51 для Java 6 и т. Д.

1 Цитата из https://en.wikipedia.org/wiki/Od_(Unix)

Поскольку мне нужно было анализировать живые банки, меня интересовала версия каждого отдельного classа в файле jar. Поэтому я взял подход Joe Liversedge к https://stackoverflow.com/a/27877215/1497139 и объединил его с таблицей версий classа https://stackoverflow.com/a/3313839/1497139 Дэвида Дж. Лизжевского, чтобы создать сценарий bash jarv, чтобы показать версии всех файлов classов в файле jar.

Применение

 usage: ./jarv jarfile -h|--help: show this usage 

пример

 jarv $Home/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar java 1.4 org.apache.log4j.Appender java 1.4 org.apache.log4j.AppenderSkeleton java 1.4 org.apache.log4j.AsyncAppender$DiscardSummary java 1.4 org.apache.log4j.AsyncAppender$Dispatcher ... 

Bash script jarv

 #!/bin/bash # WF 2018-07-12 # find out the class versions with in jar file # see https://stackoverflow.com/questions/3313532/what-version-of-javac-built-my-jar # uncomment do debug # set -x #ansi colors #http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html blue='\033[0;34m' red='\033[0;31m' green='\033[0;32m' # '\e[1;32m' is too bright for white bg. endColor='\033[0m' # # a colored message # params: # 1: l_color - the color of the message # 2: l_msg - the message to display # color_msg() { local l_color="$1" local l_msg="$2" echo -e "${l_color}$l_msg${endColor}" } # # error # # show an error message and exit # # params: # 1: l_msg - the message to display error() { local l_msg="$1" # use ansi red for error color_msg $red "Error: $l_msg" 1>&2 exit 1 } # # show the usage # usage() { echo "usage: $0 jarfile" # -h|--help|usage|show this usage echo " -h|--help: show this usage" exit 1 } # # showclassversions # showclassversions() { local l_jar="$1" jar -tf "$l_jar" | grep '.class' | while read classname do class=$(echo $classname | sed -e 's/\.class$//') class_version=$(javap -classpath "$l_jar" -verbose $class | grep 'major version' | cut -f2 -d ":" | cut -c2-) class_pretty=$(echo $class | sed -e 's#/#.#g') case $class_version in 45.3) java_version="java 1.1";; 46) java_version="java 1.2";; 47) java_version="java 1.3";; 48) java_version="java 1.4";; 49) java_version="java5";; 50) java_version="java6";; 51) java_version="java7";; 52) java_version="java8";; 53) java_version="java9";; 54) java_version="java10";; *) java_version="x${class_version}x";; esac echo $java_version $class_pretty done } # check the number of parameters if [ $# -lt 1 ] then usage fi # start of script # check arguments while test $# -gt 0 do case $1 in # -h|--help|usage|show this usage -h|--help) usage exit 1 ;; *) showclassversions "$1" esac shift done 

Компилятор Java (javac) не создает банки, он переводит файлы Java в файлы classов. Инструмент Jar (jar) создает реальные банки. Если пользовательский манифест не указан, в манифесте по умолчанию указывается, какая версия JDK использовалась для создания баннера.

вы можете найти версию компилятора Java из .class файлов с помощью Hex Editor.

Шаг 1: Извлеките файлы .class из файла jar с помощью zip-экстрактора

Шаг 2. Откройте файл .class с шестнадцатеричным редактором (я использовал плагин notepad ++ hex editor. Этот плагин читает файл как двоичный файл и показывает его в шестнадцатеричном виде). введите описание изображения здесь

В индексе 6 и 7 приведен основной номер версии используемого формата файла classа. https://en.wikipedia.org/wiki/Java_class_file

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).

В Windows выполните следующие действия:

  1. Разархивируйте или извлеките JAR-файл с помощью команды WinZip / Java JAR.
  2. Перетащите один из файлов classов в проект Eclipse Java.
  3. Откройте файл classа.

Теперь Eclipse покажет точную основную и второстепенную версию.

Я создаю небольшой скрипт bash (на github) на основе предложения Davids, используя команду file

Вы просматриваете файл манифеста примера jar:

Manifest-Version: 1.0 Создано: 1.6.0 (IBM Corporation)

  • Что эквивалентно Regex-replace-with-function-оценке в Java 7?
  • Как отключить весеннюю безопасность для определенного URL-адреса
  • Как получить доступ к параметрам задания из ItemReader, в Spring Batch?
  • intern () ведет себя по-разному в Java 6 и Java 7
  • Ошибка JNI Hello World Неудовлетворительная ссылка
  • JFreechart Loop через сектора полярных диаграмм
  • Что делает ключевое слово «assert»?
  • Как разработать алгоритм для расчета голограммы
  • Хорошая практика передачи переменных между шагами огурца-jvm
  • Простой способ получить тип classа-оболочки в Java
  • java конвертировать миллисекунды в формат времени
  • Давайте будем гением компьютера.