I'm working on a Java project and within this project I did my first try with Kotlin. I started converting some classes to Kotlin with the JavaToKoltin converter provided in the Intellij Idea. Among others my custom exceptions are now converted to Kotlin. But with this the exception handling does not work correct anymore.
If I throw one of my custom exceptions (e.g. MyCustomKotlinException.kt) within the java code, the exception is not catched (see code below).
// Example.java
package foo
import java.util.*;
import java.lang.*;
import java.io.*;
import foo.MyCustomKotlinException;
class Example
{
public static void main (String[] args)
{
try {
// Do some stuff
// if Error
MyCustomKotlinException e = new MyCustomKotlinException("Error Message");
throw e;
} catch (MyCustomKotlinException e) { // <-- THIS PART IS NEVER REACHED
// Handle Exception
} catch (Throwable e) {
e.printStackTrace(); <-- This is catched
} finally {
// Finally ...
}
}
}
So can anyone explain to me why the exception is not catch. MyCustomKotlinException is inheriting from Kotlins RuntimeException, which is just an alias to java.lang.RuntimeException.
// MyCustomKotlinException.kt
package foo
class MyCustomKotlinException(err: String) : RuntimeException(err)
Update:
I split the throw part into 2 lines (instance creation and throwing) and found that the problem is not the throwing. The try block is left after the instance creation. Is anything wrong with my instance creation of this Kotlin class?
Update2:
I added a second catch block with Throwable and the following Throwable is caught.
java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
...
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
Update3:
Changed the title to correct error and fixed problem with adding all project files to jar (see answer below).
Adding the Kotlin runtime lib to gradle does not work for me.
Adding all project files to the jar fixed the problem for me. I added the following line to my build.gradle
jar {
manifest {
attributes ...
}
// This line of code recursively collects and copies all of a project's files
// and adds them to the JAR itself. One can extend this task, to skip certain
// files or particular types at will
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
Update: Changed configurations.compile.collect to configurations.compileClasspath.collect according to this answer below.
You need to configure your project with kotlin.
So in Android Studio:
click on Tools => kotlin => Configure kotlin in project
Then in dialog check : All module containing kotlin files
and select version
press ok
Done.
This error is likely due to the fact that the simple jar task doesn’t take all its runtime dependencies.
From gradle documentation, In your build.gradle.kts you can either create a "fatJar" task or add that to your jar task:
tasks.withType<Jar> {
// Otherwise you'll get a "No main manifest attribute" error
manifest {
attributes["Main-Class"] = "com.example.MainKt"
}
// To avoid the duplicate handling strategy error
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
// To add all of the dependencies
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
}
I'm going to say that you're trying to run Kotlin code without the kotlin-runtime library
Check which system you're using and add the neccesary jar file. You can verify that this is your issue by packaging your project into a .jar file and running it with the runtime library
Thanks for the comment. Indeed compile is deprecated. However the accepted answer does not work with implementation. So I looked up the java library plugin configuration and implementation depends on compileClasspath.
So my solution for now is to add
jar {
manifest {
attributes ...
}
// This line of code recursively collects and copies all of a project's files
// and adds them to the JAR itself. One can extend this task, to skip certain
// files or particular types at will
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
with
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50"
//...
}
I feel like this should be done by the org.jetbrains.kotlin.jvm plugin.
Using compile instead of implementation in the dependencies of the build.gradle file solved it for me.
Had the same problem, compiling my project with Ant in console. I've edded kotlin-stdlib.jar into classpath and problem has gone.
Adding the following solved the issue for me:
dependencies {
"kotlinCompilerClasspath"(fileTree("libs/gradle-plugins/kotlin"))
}
Here is the content of libs/gradle-plugins/kotlin:
annotations-13.0.jar
commons-codec-1.9.jar
commons-logging-1.2.jar
gradle-download-task-3.4.3.jar
gson-2.8.5.jar
httpclient-4.5.3.jar
httpcore-4.4.6.jar
kotlin-android-extensions-1.3.40.jar
kotlin-annotation-processing-gradle-1.3.40.jar
kotlin-build-common-1.3.40.jar
kotlin-compiler-1.3.40.jar
kotlin-compiler-embeddable-1.3.40.jar
kotlin-compiler-runner-1.3.40.jar
kotlin-daemon-client-1.3.40.jar
kotlin-gradle-plugin-1.3.40.jar
kotlin-gradle-plugin-api-1.3.40.jar
kotlin-gradle-plugin-model-1.3.40.jar
kotlin-reflect-1.3.40.jar
kotlin-runtime-1.2.71.jar
kotlin-script-runtime-1.3.40.jar
kotlin-scripting-common-1.3.40.jar
kotlin-scripting-compiler-embeddable-1.3.40.jar
kotlin-scripting-compiler-impl-embeddable-1.3.40.ja
kotlin-scripting-jvm-1.3.40.jar
kotlin-stdlib-1.3.40.jar
kotlin-stdlib-common-1.3.40.jar
kotlin-stdlib-jdk7-1.3.40.jar
kotlin-stdlib-jdk8-1.3.40.jar
kotlinx-coroutines-core-1.1.1.jar
org.jetbrains.kotlin.jvm.gradle.plugin-1.3.40.jar
trove4j-1.0.20181211.jar
The complete gradle.build.kts (offline setup):
buildscript {
dependencies {
classpath(fileTree("libs/gradle-plugins/kotlin"))
}
}
plugins {
java
`java-library`
}
apply(plugin = "kotlin")
version = "2019.06.1"
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "12"
}
repositories {
flatDir {
dirs("libs/compile")
dirs("libs/provided")
}
}
dependencies {
"kotlinCompilerClasspath"(fileTree("libs/gradle-plugins/kotlin"))
compileOnly(":javaee-api-8.0")
api(":kotlin-stdlib-common-1.3.40")
api(":kotlin-stdlib-1.3.40")
api(":kotlin-stdlib-jdk7-1.3.40")
api(":kotlin-stdlib-jdk8-1.3.40")
api(":gson-2.8.5")
}
In my case, a enableFeaturePreview in the settings.gradle caused this issue when migrating to Kotlin 1.3.
In my case adding maven Bom file worked. It does job of downloading and keeping all the kotlin dependencies in sync.
imports {
mavenBom 'org.jetbrains.kotlin:kotlin-bom:<<KOTLIN_VERSION>>'
}
Refer the official documentation here :
https://kotlinlang.org/docs/gradle-configure-project.html#other-ways-to-align-versions
Related
this is what the ideal build script I have:
I do want to execute tasks "unzip_natives_os" manually. But it seems it only works at config phase. And when I take a test run with this set-up it gives me an error: "java.lang.UnsatisfiedLinkError" but if I change the configuration from "nativesOS" into "runtimeOnly" inside of the dependencies block, it works fine. Do I have to explicitly create this "applicationDefaultJvmArgs" and insert the libraryPath of the natives. Is there any other way? And when I need to unzip the "nativesOS" config it needs an explicit version, it seems it did not see the platform/BOM?
// build.gradle.kts
val nativesOS : Configuration by configurations.creating {
this.isTransitive = false
this.extendsFrom(configurations.runtimeOnly.get())
}
dependencies {
implementation(platform("org.lwjgl:lwjgl-bom:3.2.3"))
listOf(
"", "-assimp", "-openal",
"-opengl", "-glfw"
).map { lib ->
implementation("org.lwjgl:lwjgl$lib")
// I give it an explicit version, because it would not work if I unzip this.
nativeOS("org.lwjgl","lwjgl$lib", "3.2.3", classifier = LWJGL.lwjglNatives)
}
...
}
// unzip_native_os tasks, here is the problem.
tasks.register<Copy>("unzip_native_os") {
this.group = "zip"
doLast {
nativesOS.asFileTree.filter { it.name.contains("natives") }.forEach {
unzipTo(File("$buildDir/libs/natives-os"), it)
}
}
}
Edited: Why this is not working? I config it first then execute it.
tasks.register<Copy>("unzip_native_os") {
this.group = "zip"
val nativesJar = nativesOS.asFileTree.filter { it.name.contains("natives") }.files
doFirst {
nativesJar.forEach {
println(">>>> $it")
unzipTo(File("$buildDir/libs/natives-os/v2"), it)
}
}
}
Edited: I found a possible answer and it looks promising but I did not implement it yet, because I need some learning to do on building this kind of script plugin/inline plugin. Here's the link: gradle custom task execution phase
Edited: found an alternative/another quick solution here: Fix custom tasks in gradle. Want to run it manually via at Execution Phase
Context: To create multiple executable jar's from a single project - multiple package gradle project
Issue: I refer to the solution provided in Link, this helps in generating the jar in build->libs folder, but when I try executing the jar nothing happens
Note: Even if I make the package name same as java file name, the generated jar does not execute.
Also I notice the file size of all the jar's generated is the same. Hope the issue faced is clear & await inputs as to where I am making a mistake.
My Project Structure (illustrative purpose):
ProjectA
-src
--main
---java
----pkg1
-----pkgCalculator
------Calculator.java
-----pkgScale
------Scale.java
----pkg2
-----pkgMusicPlayer
------MusicPlayer.java
-----pkgVideoPlayer
------VideoPlayer.java
---resources
----fxml
----css
--test
---java
---resources
Gradle file (relevant portion below, rest as per the link above ):
artifacts {
archives jarPackage("pkgCalculator", "1.0"),
jarPackage("pkgScale","1.0"),
jarPackage("pkgMusicPlayer","1.0"),
jarPackage("pkgVideoPlayer","1.0")
}
After discussion with #iCoder, first part of the issue has been solved: the jarPackage function could not be reused "as is", and had to be adapted to support generic class/package layout:
def jarPackage(String jarName, String className, artifactVersion) {
if (artifactVersion == "" || artifactVersion == null) {
artifactVersion = "1.0.0"
}
return tasks.create("jar${jarName}", Jar) {
baseName = jarName
version = artifactVersion
def String pkgName = className.substring(0, className.lastIndexOf("."))
def String pkgDir = pkgName.replaceAll("\\.", "/")
def String clazzName = className.substring( className.lastIndexOf(".") +1 )
from(sourceSets.main.output) {
include "$pkgDir//**"
}
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes "Implementation-Title": "$clazzName",
"Implementation-Version": "$version",
"Main-Class": "$pkgName.$clazzName"
}
}
}
artifacts {
archives jarPackage("calculator", "pkg1.pkcalculator.Calculator" , "1.0.0")
}
Another issue remains, not related to Gradle but to JDK 11 linkage problem: #iCoder you should open another question for that remaining problem, if not fixed yet.
I'm trying to work out how I get a Groovy test script to import a Java class during the testing phase ...
Specifically I want to use JavaFXThreadingRule: .java file from here (or rather here and so included in my Java test source path) and then import it in my Groovy test script to use as an annotation.
The Groovy test script path is src\test\ft\groovy\core\testscript.groovy.
The .java file is src\test\ft\java\core\JavaFXThreadingRule.java.
The package line I've used in both is "package core;"
My "sourceSets" clause in build.gradle looks like this:
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
java {
srcDirs = ['src/test/ft/java' ]
}
groovy {
srcDirs = ['src/test/ft/groovy', 'src/test/ut/groovy']
}
}
}
Interestingly the build.gradle output shows that the compileTestJava task is run before the compileTestGroovy task ... and yet I get
unable to resolve class core.JavaFXThreadingRule # line 18, column 1.
import core.JavaFXThreadingRule ^
NB I also tried "import JavaFXThreadingRule" - same result.
In addition to just wanting to resolve the problem I'm also wondering how Gradle decides what order to do the tasks compileTestJava and compileTestGroovy... and whether I shouldn't perhaps make my compileTestGroovy explicitly dependent on compileTestJava...
Thanks to Tim Yates I found the "workaround" of putting this Java file in with the Groovy ones... but this answer gave me another clue, and I then changed my build.gradle to be like this:
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
groovy {
srcDirs = ['src/test/ft/groovy', 'src/test/ut/groovy', 'src/test/ft/java' ]
}
}
}
... works ... no doubt obvious to old Gradle hands.
That question and answer referenced above were talking about the app code classes (and Gradle tasks). Unless some Gradle expert can say otherwise I'm assuming that the Groovy test compile task and Java test compile task are completely separate and can't "see" one another's classes...
I am looking for a solution to exclude certain files marked with a particular annotation to be packaged in jar (can be compiled but not part of jar created).
I have tried the following steps
Create a ClassLoader using : sourceSets.main.output + configurations.runtime
Check recursively within the compiled classes, use ClassLoader.loadClass to load the class and check if annotation is present (Class.isAnnotationPresent)
Any pointers would be helpful.
I was able to implement this long time back but forgot I had posted the question here.
The solution I used to was actually quite simple -
Using gradle jar task -
jar {
excludes = excludedFiles(sourceSets.main.allSource.files)
baseName = artifactName
version = artifactVersion
}
And define the excludedFiles function to look up the files in the source directory provided -
def excludedFiles(Collection<File> files) {
List<String> classes = new ArrayList<>()
files.each { file ->
if (file.isDirectory()) {
excludedFiles(Arrays.asList(file.listFiles()))
}
else {
if (file.text.contains("#YourAnnotation") && file.text.contains("import foo.bar.YourAnnotation")) {
classes += getClassName(file.absolutePath)
}
}
}
return classes
}
Hope this helps.
I have a newbie question on a gradle java project. I wish to configure the output artifact jar of this to only include certain classes from my project. I have the desired classes to be included in a file say classes.txt that is generated as a part of a separate task. How should one configure the jar task of the gradle build so that does this. This is what I have tried so far:
jar {
// reset actions
actions = []
copy {
def dependentClasses = file("classes.txt")
if (dependentClasses.exists()) {
dependentClasses.eachLine { include it }
}
from sourceSets.main.output
includeEmptyDirs = false
into "build/tmp/jar" //Some temporary location
}
// How to zip the contents?
}
I am sorry for the possibly naive question, but I haven't had luck with the other solutions seen.
Thanks!
It can be done in the following way:
apply plugin: 'java'
jar {
def excluded = project.file('classes.txt').readLines()
exclude { f ->
excluded.any { e -> f.path.replaceAll(File.separator, '.').contains(e) }
}
}
Demo can be found here, Lol1.class will be excluded.
Using Opal's answer, here is the answer for the include of files
apply plugin: 'java'
jar {
def included = project.file('classes.txt').readLines()
include { f ->
included.any { i -> f.isDirectory() ? true : f.path.replaceAll(File.separator, '.').contains(i) }
}
}
The slight trick was that the FileTreeElement f being passed to the closure also has the package directory passed and if that happens to return false, the subtree below is not traversed and hence the check on it being a directory to return true to enable processing of the subtree.
Demo for solution is here and Lol1.class will be included. Thanks for the help, Opal!