Kotlin multiplatform library exporting dependencies for JVM - kotlin

I’m creating a multiplatform for jvm and iOS on kotlin using Gradle.
For the jvm, even if I define my dependencies as implementation, they are included in the library generated .pom and with runtime scope.
By using implementation, I was expecting that these dependencies are not passed to the library consumer.
But, when I use this library on my other jvm project, Gradle is importing the library-specific version. Not the one that I set in my application dependencies.
in this case, I'm doing a downgrade. The library is using the dependency version 1.4.1, and on the application I want to use version 1.4.0.1.

By using implementation, I was expecting that these dependencies are not passed to the library consumer.
If you expect the consumers to provide those transitive dependencies themselves, you should use compileOnly instead of implementation.
The difference between api and implementation is that transitive dependencies declared with api will be visible and usable by the application by just depending on your library (seen at compile time AND runtime). With implementation, the transitive dependency will still be here at runtime but will not be visible on the compile classpath of the consuming application, so you cannot use the transitive dependency's declarations in the application's code.
Have a look at the table here:
https://docs.gradle.org/current/userguide/java_library_plugin.html
If you stick with implementation, you can still force a version for the transitive dependency in Gradle by using strictly or by excluding it and redeclaring it yourself. See the doc:
https://docs.gradle.org/current/userguide/dependency_downgrade_and_exclude.html

Related

What does "common" mean in kotlin documentation?

In kotlin standard library documentation i can see the following filters:
As far as i can gather, JVM means that internals of a package can be compiled into byte code, JS into javaScript and Native into binaries. But what does "Common" mean ?
Common means available for all platforms. It is an API that you can use directly in platform independent code in Kotlin Multiplatform projects.
Kotlin Multiplatform allows you to write common Kotlin code for multiple different platforms. For example, you could have a project with an Android app (using Kotlin/JVM for native Android applications) and a web interface (using Kotlin/JS). Then, you could share code between both subprojects.
As you have guessed correctly, JVM means it is available using Kotlin/JVM (compiling to Java bytecode).
If it is marked with JS, it is available for Kotlin/JS which transpiles the Kotlin code to JavaScript.
Finally, Native means it is available when using Kotlin/Native. This is different from compiling with native-image, which compiles JVM bytecode to native executables. For that, you would still use Kotlin/JVM.
If you write code in "common", then it can be compiled into any of the other targets, so you can share Kotlin code amongst the different platforms you are targeting. You can read more in the documentation.

Difference between Kotlin plugins

What are the difference between this three Kotlin plugin and what they actually do?
plugins {
id 'kotlin-android'
id 'org.jetbrains.kotlin.android'
id "org.jetbrains.kotlin.jvm" version "1.6.20"
}
The third one seems to be the recommended way specially when using Kotlin Coroutines
These plugins provide integration with different other Gradle plugins. They both setup compiling Kotlin for the JVM, but aim to interoperate with different other tools.
org.jetbrains.kotlin.android or kotlin-android
This plugin offers integration of Kotlin with the Android Gradle plugin, which should also be applied to the project. The Kotlin compilations are set up to be included in the builds of Android variants (e.g. debug, release, testDebug etc.)
The IDs kotlin-android and org.jetbrains.kotlin.android designate the same Gradle plugin. The only difference is that the "full" ID org.jetbrains.kotlin.android can be used for resolving the plugin from the Gradle Plugin Portal, while the shorter ID kotlin-android can only be used for applying the plugin if you already have it on the build classpath (i.e. it's added elsewhere).
org.jetbrains.kotlin.jvm (also has a shorter alias kotlin)
This is the plugin for building Kotlin projects that target JVM without Android support.
The plugin offers integration with the Gradle java plugin (as well as java-library or application). The project that applies this plugin can also use Java sources. The Kotlin compilations are wired with the java plugin's source sets (main and test by default)
Normally you should only apply one of these plugins, depending on whether you target Android or "standard" JVM. If you need to target both platforms, you should use the Kotlin Multiplatform plugin by ID org.jetbrains.kotlin.multiplatform, which adds the DSL to setup the targets in the project. Those might include jvm() and android(), as well as other targets: JS, WASM, Kotlin/Native.

kotlin-test vs kotlin-test-junit

I have a kotlin project that is compiled to java.
My test library is junit.
Im using maven as my dependency management and Intellij IDEA.
recently I got that strange warning in my pom.
Inspection info: If you have kotlin-test and junit dependency then
most likely you better to include kotlin-test-junit instead of just
kotlin-test
What is the difference between kotlin-test and kotlin-test-junit?
from what I read it seems that kotlin-test is not deprecated, so Why did intellij recommend kotlin-test-junit instead of kotlin-test?
So I found the answer here (I don't understand how I missed it in my first search)
In short kotlin-test library provides a set of annotations and utility functions independently of the test framework.
Where kotlin-test-junit library provides an implementation on top of Junit Asserter and the annotations and utility functions kotlin-test provides.

gradle custom dependency resolution

Is it possible to bypass Ivy (or whatever else Gradle uses internally for dependency resolution) and still keep the same dependency DSL? I'm trying to develop a plugin for resolving native dependencies that would use the system's package manager to install dependencies, but Gradle's RepositoryHandler only allows Ivy, Maven, or flat dir repositories.
If you want to completely bypass Gradle's dependency resolution system, then you'll also have to create your own DSL. To do so, you would use Gradle concepts such as "extension objects" and "domain object containers".

How do I combine library code and a maven plugin in same project?

Can I make a single maven project that can be included as a dependency (to reference Java classes inside) and executed as a plugin?
I'm working on a library to help with hosting GWT on a LAMP stack. For someone to use this, they need to extend some Java classes (so it must be a dependency) and they need to invoke a maven plugin (so it needs to be a plugin). The plugin code references the same Java classes, so if they are seperate projects, the plugin one must depend on the library one.
As is, I have the library as a normal maven project, and the plugin as a maven plugin that depends on the library. This means that to do a release, I have to release two different artifacts, and the dependent project must update both version numbers for both artifacts. It'd be nice to have a single project.
You'd be better of by doing the following
project for the jar, Foo:Foo.jar
project that uses Foo:Foo.jar as a
dependency that builds the plugin
Maven parent project that
builds 1&2
The directory structure would look like this
\project\pom.xml
\project\foo\pom.xml
\project\foo\src\main\java\foo.java
\project\plugin\pom.xml
\project\plugin\src\main\resources
\project\plugin\src\main\java
From \project you can do a mvn clean package to build \project\foo\target\foo.jar and \project\plugin\target\plugin.jar
Hope this helps.
If you create a maven plugin it still has a artifactId/groupId/version. There's no reason it can't be references both in your section and in your section. On the other hand, if thats ugly, why not just make a library with the common code that both your main project and your maven plugin project depend on?
EDIT:
Sorry, wasn't clear on the second part. Look into composite maven projects, where there is a top level pom that defines a number of child modules. In this case, the maven plugin and the common library code could be separate children producing separate artifacts, but you only need one version number and one release command executed from the top level. I haven't done this but there are any number of open source projects that do. its often used as an idiom to put testing code into a single module that can be referenced by all the others, without having it go out in any distributable jar.
The best practice is to not do what you're suggesting. Examples of this include PMD, BND, JUnit/TestNG, and so on - no serious projects seem to package the maven plugin with the library proper.
One way to get both alternatives is to use maven assemblies to have two seperate maven projects for each the library proper and the plugin and then a separate packaging as a jar containing the classes from both.