# Multi-platform project with a JVM common target

**URL:** <https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032>\
**Category:** Multiplatform\
**Created:** [March 19, 2019, 2:46pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032 "2019-03-19T14:46:29Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![benwoodworth](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@benwoodworth](https://discuss.kotlinlang.org/u/benwoodworth)\
**Post date:** [March 19, 2019, 2:46pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/1 "2019-03-19T14:46:29Z")

</div>

I’m working on a JVM project that can be compiled against a couple different Java APIs. I’d like to use Kotlin’s multi-platform features for this, since they look super useful for what I’m doing.

I would like to have a `common` module that targets the JVM, and some JVM targets with various JDKs that use `common` to share code.

The build script I’m playing around with below. It can’t execute because `common` depends on itself, since the `jvm` preset has a dependency on `common`. I’m also not sure if there are any issues with replacing/removing the common module (e.g. there’s something going on with a `metadata` target, which I don’t know much about).

Is there a good way to approach this kind of multi-platform project?

**settings.gradle.kts:**

```kotlin
rootProject.name = "jdk-multiplatform-test"

enableFeaturePreview("GRADLE_METADATA")

```

**build.gradle.kts:**

```kotlin
plugins {
    kotlin("multiplatform") version "1.3.21"
}

repositories {
    mavenCentral()
}

kotlin {
    // Is this a problem, since common is a default target?
    jvm("common") // JDK 6+

    jvm("javaApi0") // JDK 6+
    jvm("javaApi1") // JDK 8+

    sourceSets {
        val commonMain by getting {
            // Defined by the jvm preset, causing a circular dependency problem:
            //dependsOn(commonMain)

            dependencies {
                // May not be necessary if the jvm preset defines this.
                implementation(kotlin("stdlib"))
            }
        }

        val javaApi0Main by getting {
            dependsOn(commonMain) // May not be necessary.

            dependencies {
                // May not be necessary, since commonMain already has this.
                implementation(kotlin("stdlib")) 
            }
        }

        val javaApi1Main by getting {
            dependsOn(commonMain) // May not be necessary.

            dependencies {
                implementation(kotlin("stdlib-jdk8"))
            }
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![nbransby](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/nbransby/32/5491_2.png) [@nbransby](https://discuss.kotlinlang.org/u/nbransby)\
**Post date:** [March 23, 2019, 7:45pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/2 "2019-03-23T19:45:34Z")

</div>

Multiplatform is designed to have shared kotlin code target multiple different platforms, not sure you are going to be able to achieve what you are looking for with multi platform but then you don’t really need to use it at all if you are only targeting the JVM.

Why not just use the java-library gradle plugin and have multiple libs that depend on each other?

---

<div class="post-metadata">

**Author:** ![benwoodworth](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@benwoodworth](https://discuss.kotlinlang.org/u/benwoodworth)\
**Post date:** [March 25, 2019, 2:41pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/3 "2019-03-25T14:41:01Z")

</div>

I’m mainly after the expect/actual mechanism, and it looks like that can be used without the `kotlin("multiplatform")` plugin (which I didn’t realize). Now I’m wondering if there’s a good way to setup a JVM Kotlin project with multiple source sets, similar to how multi-platform projects are organized. That is, one common with `expect` declarations, and a few source sets with the `actual` implementations.

Specifically, I’m working on a plugin for Minecraft servers that could be for against a couple different server platforms/APIs (e.g. [Bukkit](https://bukkit.org/) and [Sponge](https://www.spongepowered.org/)). They share a lot of the same constructs, like players, blocks, and items, but have different APIs for them. Expect and actual would make sharing code between the two implementations a lot better compared to what I’m doing right now, which is creating adapters and factories for all the classes I have and providing them through dependency injection. This works, but it has a lot of complexity and overhead that could be avoided.

---

<div class="post-metadata">

**Author:** ![nbransby](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/nbransby/32/5491_2.png) [@nbransby](https://discuss.kotlinlang.org/u/nbransby)\
**Post date:** [March 25, 2019, 3:13pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/4 "2019-03-25T15:13:37Z")

</div>

I did not realize expect/actual could be used without multiplatform, although I wonder how it would work.

The adapters would still be needed in any case so you can create a consistent API surface, its the factories/DI you could do away with as you can just instantiate the adapters classes directly (as the correct actual implementation has been selected at compile time)

You can achieve the same thing without expect/actual by creating separate libs for the server platforms/APIs but with identical public API surfaces (your adapters with the exact same class names), compile your shared code against one of the libs (or a dummy/stub one) with the compileOnly gradle statement.

Then depend the correct one at the client level where you depend on the shared lib.

---

<div class="post-metadata">

**Author:** ![pdvrieze](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/pdvrieze/32/1882_2.png) [@pdvrieze](https://discuss.kotlinlang.org/u/pdvrieze)\
**Post date:** [March 27, 2019, 10:17pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/5 "2019-03-27T22:17:34Z")

</div>

What you intent to do can be done. More common in Android vs JVM targets. The support in intellij for this is however not quite there. Gradle will compile correctly as common code will actually only be compiled when compiling the target. Unfortunately it is not possible to mark a source set as being JVM so that it can JVM methods (gradle doesn’t care, Intellij does).

---

<div class="post-metadata">

**Author:** ![arkivanov](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arkivanov](https://discuss.kotlinlang.org/u/arkivanov)\
**Post date:** [March 28, 2019, 9:21pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/6 "2019-03-28T21:21:35Z")

</div>

I’m facing exactly the same issue at the moment with multiplatform project. I have common JVM source set that is used by JVM and Android targets source sets. It compiles well with Gradle, but IDEA even does not see “java” package so I can’t import “java.util.\*”. Is there any solution or workaround?

---

<div class="post-metadata">

**Author:** ![Alexey.Belkov](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/alexey.belkov/32/5215_2.png) [@Alexey.Belkov](https://discuss.kotlinlang.org/u/Alexey.Belkov)\
**Post date:** [April 8, 2019, 12:11pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/7 "2019-04-08T12:11:24Z")

</div>

There is no proper solution yet, please follow [https://youtrack.jetbrains.com/issue/KT-28194](https://youtrack.jetbrains.com/issue/KT-28194) for updates.

---

<div class="post-metadata">

**Author:** ![leaf](https://avatars.discourse-cdn.com/v4/letter/l/ec9cab/32.png) [@leaf](https://discuss.kotlinlang.org/u/leaf)\
**Post date:** [June 2, 2019, 2:43pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/8 "2019-06-02T14:43:44Z")

</div>

Need same ability, but for JS

---

<div class="post-metadata">

**Author:** ![thecodewarrior1](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/thecodewarrior1/32/6300_2.png) [@thecodewarrior1](https://discuss.kotlinlang.org/u/thecodewarrior1)\
**Post date:** [June 17, 2019, 6:00pm UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/9 "2019-06-17T18:00:31Z")

</div>

Well that’s unfortunate. As I just commented on the issue, this doesn’t seem like a very hard feature to implement. At the moment I imagine there’s _extra_ code required in order to enforce the lack of a platform. All this would need is to have that restraint removed and a minor gradle api added.

Am I mistaken and it’s actually much more complex than that?

---

<div class="post-metadata">

**Author:** ![pdvrieze](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/pdvrieze/32/1882_2.png) [@pdvrieze](https://discuss.kotlinlang.org/u/pdvrieze)\
**Post date:** [June 19, 2019, 4:47am UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/10 "2019-06-19T04:47:47Z")

</div>

As far as I recall it is possible to manually set the target platform of a module (until the next gradle sync). That allows the jdk classes to be found.

---

<div class="post-metadata">

**Author:** ![thecodewarrior1](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/thecodewarrior1/32/6300_2.png) [@thecodewarrior1](https://discuss.kotlinlang.org/u/thecodewarrior1)\
**Post date:** [June 19, 2019, 5:45am UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/11 "2019-06-19T05:45:05Z")

</div>

That works, but then all the `expect` declarations throw errors in IDEA about missing implementations and when going to implement them only gives the option of putting the `actual` definitions in the same module.

Basically it goes back to being just three normal modules without any of the conveniences of full multiplatform support.

---

<div class="post-metadata">

**Author:** ![pdvrieze](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/pdvrieze/32/1882_2.png) [@pdvrieze](https://discuss.kotlinlang.org/u/pdvrieze)\
**Post date:** [June 19, 2019, 6:12am UTC](https://discuss.kotlinlang.org/t/multi-platform-project-with-a-jvm-common-target/12032/12 "2019-06-19T06:12:51Z")

</div>

You can do common code without expect/actual definitions, but indeed intellij doesn’t really cater well for this approach yet. In my project I use it as it is only a small part and generally multiplatform anyway (there is a proper common module and then a sourceset shared between android and java).
