Я живу в подобной ситуации время от времени в течение последних нескольких лет.
Чтобы понять это, я создал пример мини-проекта со следующим файлом build.gradle
:
apply plugin: 'groovy'
repositories {
jcenter()
mavenCentral()
}
dependencies {
compile "org.codehaus.groovy:groovy:2.4.15"
}
if (JavaVersion.current() != JavaVersion.VERSION_1_6) {
// findJava6Jvm is defined in java-versions.gradle
// and returns a gradle JavaInfo instance.
def java6Jvm = findJava6Jvm()
if (!rootProject.ext.has('hasPrintedJavaVersionNote')) {
println "**************** java version notice ****************"
println "NOTE: the gradle process and the source compilation"
println " are using different versions of java:"
println ""
println " gradle process uses: ${JavaVersion.current()}"
println " source complilation uses: 1.6"
println ""
println "*****************************************************"
rootProject.ext.hasPrintedJavaVersionNote = true
}
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
tasks.withType(AbstractCompile) {
options.with {
fork = true
forkOptions.executable = java6Jvm.javacExecutable
}
}
tasks.withType(GroovyCompile) {
groovyOptions.with {
fork = true
}
}
tasks.withType(Javadoc) {
executable = java6Jvm.javadocExecutable
}
tasks.withType(Test) {
executable = java6Jvm.javaExecutable
}
tasks.withType(JavaExec) {
executable = java6Jvm.javaExecutable
}
}
def findJava6Jvm(Closure extraUsage = null) {
if (JavaVersion.current().isJava6()) {
// if we are already using java 6 to launch gradle, just return
// the javac for the current jvm
return org.gradle.internal.jvm.Jvm.current()
}
def failOnCondition = { condition, msg ->
if (condition) {
println """
Executing the gradle build with a JDK different from java 1.6
(i.e. java 7, 8, etc) requires that you provide the build
with enough information so that it can still locate a java 1.6
jdk for source code compilation.
If the build can not locate a java 6 jdk, you can help it out by
specifying one of the following properties:
JAVA_HOME_6 environment variable (example: \"export JAVA_HOME_6=/usr/lib/jvm/java-6/\")
JAVA_HOME_6 system property (-DJAVA_HOME_6=<path>)
JAVA_HOME_6 gradle project property (-PJAVA_HOME_6=<path>)
""".stripIndent()
if (extraUsage != null) {
extraUsage()
}
println msg.stripIndent()
throw new GradleException("No 1.6.x jdk found!")
}
}
def name = 'JAVA_HOME_6'
def custom = [System.env[name], System.properties[name], properties[name]].find { it }
failOnCondition !custom, """
ERROR: Please set the JAVA_HOME_6 property in one of the above specified
ways"""
def jdkDir = file(custom)
failOnCondition !jdkDir.isDirectory(), """
ERROR: The configured JAVA_HOME_6 setting:
$custom
does not point to a directory on the local file system.
Please set this variable to the JAVA_HOME of a 1.6.x
jdk"""
def fs = File.separator
def jdkJavac = file("$jdkDir${fs}bin${fs}javac").canonicalFile
if( !jdkJavac.isFile() ) jdkJavac = file( jdkJavac.path + ".exe" )
failOnCondition !jdkJavac.isFile(), """
ERROR: Could not locate a bin/javac executable file under
the configured JAVA_HOME_6 setting:
$custom \n"""
def process = [jdkJavac, "-version"].execute()
process.waitForOrKill(5000)
def version = process.err.text.readLines().first()
failOnCondition !version?.contains('1.6.'), """
ERROR: The configured JAVA_HOME_6 setting:
$custom
points at a non 1.6 jdk, 'java -version' reports $version!"""
// after all the validations pass, reutrn the jdk javac path
org.gradle.internal.jvm.Jvm.forHome(jdkDir)
}
и поместил класс в вашем вопросе в файл по адресу:
java-version-experiment ~> tree src/
src/
└── main
└── groovy
└── com
└── somepackage
└── SomeGroovyClass.groovy
Учитывая вышесказанное, когда я запускаю gradle-компиляцию моего источника с использованием java 8:
java-version-experiment ~> export JAVA_HOME_6=/usr/lib/jvm/java-6_121-oracle
java-version-experiment ~> setjava java-8-oracle
PATH updated - JAVA_HOME=/usr/lib/jvm/java-8-oracle
java-version-experiment ~> gradle -v
------------------------------------------------------------
Gradle 4.10.2
------------------------------------------------------------
Build time: 2018-09-19 18:10:15 UTC
Revision: b4d8d5d170bb4ba516e88d7fe5647e2323d791dd
Kotlin DSL: 1.0-rc-6
Kotlin: 1.2.61
Groovy: 2.4.15
Ant: Apache Ant(TM) version 1.9.11 compiled on March 23 2018
JVM: 1.8.0_201 (Oracle Corporation 25.201-b09)
OS: Linux 4.18.0-17-generic amd64
java-version-experiment ~> gradle build
> Configure project :
**************** java version notice ****************
NOTE: the gradle process and the source compilation
are using different versions of java:
gradle process uses: 1.8
source complilation uses: 1.6
*****************************************************
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
java-version-experiment ~>
, кажется, что класс скомпилирован с использованием java 6. В linux вы можете проверитьэто с помощью шестнадцатеричного редактора командной строки для файлов классов:
~> od -j 7 -N 1 -t d1 build/classes/groovy/main/com/somepackage/SomeGroovyClass.class
0000007 50
0000010
~>
, который, по сути, извлекает байт 7 (с нуля) из файла класса, где 50
- это то, что нас интересует. Соответствующая версия Javaчисла:
Java 6 uses major version 50
Java 7 uses major version 51
Java 8 uses major version 52
Java 9 uses major version 53
Java 10 uses major version 54
Java 11 uses major version 55
другими словами, мне кажется, что использование forkOptions.executable
в задаче компиляции работает, и классы действительно компилируются с использованием Java 6.
Однако этоМне также кажется, что утечки классов.Под этим я подразумеваю, что кажется, что даже если вы компилируете с использованием исполняемого файла java 6, путь к классу java 8 и API-интерфейсы просачиваются в процесс компиляции.
Как вы заявили, вышеприведенная компиляция должна была завершиться неудачей, но этого не произошло.Я все еще в растерянности относительно того, почему это происходит, и, что более важно, как предотвратить утечку пути к классам.
Любые гуру-грейдеры, пожалуйста, не стесняйтесь звонить сюда, мне было бы очень интересно разобраться в этом вопросе.
<< edit >>
Обнаружил следующее:
Компиляция и тестирование для Java 6 или Java 7
Компилятор Groovy всегда будетвыполняться с той же версией Java, которая использовалась для запуска Gradle.Вы должны установить sourceCompatibility и targetCompatibility на 1.6 или 1.7.Если у вас также есть исходные файлы Java, вы можете выполнить те же шаги, что и для подключаемого модуля Java, чтобы убедиться, что используется правильный компилятор Java.
в документации по gradle по адресу:
https://docs.gradle.org/current/userguide/groovy_plugin.html
Так что это кажется невозможным для заводной.Седьмой байт в файле классов, кажется, управляется настройкой:
targetCompatibility = JavaVersion.VERSION_1_6
, т.е. даже при использовании чистой Java 8 и установке targetCompatibility мы получаем 50
в байте основной версии класса.
<< edit 2 >>
проверил, что это работает для файлов Java.Добавлен java-файл под src/main/java/com/somepackage/SomeJavaClass.java
с тем же файлом сборки, что и выше, для настройки сценария компиляции с двумя виртуальными машинами.
Результат:
gradle clean build
> Configure project :
**************** java version notice ****************
NOTE: the gradle process and the source compilation
are using different versions of java:
gradle process uses: 1.8
source complilation uses: 1.6
*****************************************************
> Task :compileJava FAILED
/home/mbjarland/projects/java-version-experiment/src/main/java/com/somepackage/SomeJavaClass.java:5: cannot find symbol
symbol : class Optional
location: class com.somepackage.SomeJavaClass
public Optional<String> someJavaMethod() {
^
/home/mbjarland/projects/java-version-experiment/src/main/java/com/somepackage/SomeJavaClass.java:6: cannot find symbol
symbol : variable Optional
location: class com.somepackage.SomeJavaClass
return Optional.empty();
^
2 errors
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed with exit code 1; see the compiler error output for details.
BUILD FAILED in 1s
2 actionable tasks: 2 executed
- это то, что вы ожидаете.
Заключение после долгого исследования: это работает для файлов Java, как и ожидалось, невозможно для файлов Groovy.