Как мне создать банку со всеми зависимостями, используя Gradle 4.4? - PullRequest
0 голосов
/ 27 июня 2018

Этот вопрос относится к этому .

Я получил задание Gradle:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from { 
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

И есть только одна зависимость, за исключением тестовых зависимостей:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testImplementation group: 'junit', name: 'junit', version: '4.12'
}

Запуск из IDE работает нормально. Однако при развертывании на Raspberry Pi (или использовании локальных результатов jar gradlew fatJar) я получаю следующее исключение:

$ java -jar java-sense-hat-1.0a.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
    at io.github.lunarwatcher.pi.sensehat.UtilsKt.getSenseHat(Utils.kt:18)
    at io.github.lunarwatcher.pi.sensehat.SenseHat.<init>(SenseHat.java:12)
    at io.github.lunarwatcher.pi.sensehat.Tests.main(Tests.java:9)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
    at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
    ... 3 more

Который запускается этой строкой:

return Optional.empty()

в методе Котлина, возвращающем Optional<File>. Ответ на связанный вопрос :

Любая среда выполнения kotlin должна находиться в пути к классам и проверяться с помощью $ echo $ CLASSPATH.

Или вам нужно добавить kotlin-runtime в maven, а затем собрать внутри самого фляги с помощью компиляции mvn: single,

Это означает, что среда выполнения kotlin не включена в путь к классам. Прежде чем вы ответите «добавьте kotlin-runtime к вашим зависимостям», это часть stdlib :

Kotlin Runtime (устарело, используйте вместо этого артефакт kotlin-stdlib)

Я использую kotlin-stdlib-jdk8, и он работает в IDE. Просто для тестирования использование kotlin-stdlib вместо этого ничего не меняет.

Кроме того, замена implementation на compile исправляет это.

В посте, на который я ссылался вверху вопроса, есть предложение использовать runtime в задании fatJar. Итак:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

Зависимость по-прежнему не включена, и программа вылетает.

Так почему бы не добавить реализацию в качестве конфигурации для копирования?

Я пытался. Я закончил с этим:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
        configurations.implementation.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

И исключение:

Непосредственное разрешение конфигурации 'реализация' не разрешено

Итак, учитывая:

  • compile вместо implementation работает
  • Исключением времени выполнения является то, что Kotlin не находится в пути к классам
  • Работает в IDE
  • При добавлении предложения implementation к задаче fatJar компиляция завершается с отдельным исключением

Как создать банку со всеми зависимостями в Gradle 4.4 при использовании ключевого слова implementation? ​​


Обработка предложенного дубликата: он работает только с ключевым словом compile, а не implementation. Кроме того, compile устарела в пользу implementation и api, поэтому использование compile вместо implementation при объявлении зависимости не вариант.

1 Ответ

0 голосов
/ 27 июня 2018

Вы пробовали Shadow Plugin как:

shadowJar {
  manifest {
     attributes 'Implementation-Title': 'rpi-sense-hat-lib',
            'Implementation-Version': version,
            'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
  }
  configurations = [project.configurations.compile, project.configurations.runtime]
}

Edit:

Вы также можете сделать это (как описано в ответе на этот вопрос ):

configurations {
    fatJar
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testImplementation group: 'junit', name: 'junit', version: '4.12'

    fatJar "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                'Implementation-Version': version,
                'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.fatJar.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

но затем вы должны повторить все зависимости реализации как зависимости fatJar. Для вашего текущего проекта это хорошо, так как у вас есть только одна зависимость, но для чего-то большего это станет беспорядком ...

Редактировать 2:

Как отметил @Zoe в комментариях, это также приемлемое решение:

task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'rpi-sense-hat-lib',
                   'Implementation-Version': version,
                   'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
    }
    baseName = project.name
    from {
        configurations.runtimeClasspath.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    with jar
}

однако в соответствии с исходным кодом обратите внимание, что runtimeClasspath представляет собой комбинацию runtimeOnly, runtime и implementation, что может быть или не быть желательным в зависимости от ситуации, например Возможно, вы не захотите включать runtime зависимостей, потому что они предоставляются контейнером.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...