Expected class has no actual declaration - intellij-idea

I am doing a multiplatform project.
A part of my gradle file looks like this
...
kotlin {
jvm()
jvm("api")
js()
mingwX64("mingw")
sourceSets {
...
val jvmMain by getting {
dependencies {
implementation ("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
}
}
val jvmTest by getting {
dependencies {
implementation ("org.jetbrains.kotlin:kotlin-test")
implementation ("org.jetbrains.kotlin:kotlin-test-junit")
}
}
val apiMain by getting {
dependencies {
dependsOn(jvmMain)
}
}
val jsMain by getting {
dependencies {
implementation ("org.jetbrains.kotlin:kotlin-stdlib-js")
}
}
...
}
}
Now in the commonsMain sources I get an IDE error (red underline) that says "expected class Sample has no actual declaration in apiMain", but apiMain depends on jvmMain which has the actual declaration.
I don't think I need an actual declaration in apiMain since I already have one in jvm.
Should I take a different approach in setting-up my source sets?
Anyway the project compiles fine and I can run apiMain, but the IDE error really annoys me.

This is a known IDE bug. See YouTrack ticket here.
For now, you can use #Suppress("NO_ACTUAL_FOR_EXPECT") to get rid of the warning in your IDE. I wouldn't really recommend it though, because you'll get a runtime crash instead of a compile-time error if you're missing any actual implementations.

They should be under the same package name.
Also check if your package name is the same as the one you get the error
expected class Sample has no actual declaration in apiMain
You need to have the package apiMain.
In my case I had
And I had to create both folders in resources

In my case, it turns out that something in my ".idea" folder had gotten corrupted. I closed Android Studio, deleted that directory from the root of my project and then reopened the project. The .idea file was automatically re-created and my problem was gone.
I figured this out because creating a new KMM app using the wizard didn't have the same error that I was seeing with expect/actual classes.

Related

unresolved supertypes: javax.sql.DataSource

I am seeing the following error when trying to compile using gradle.
Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
class com.zaxxer.hikari.HikariDataSource, unresolved supertypes: javax.sql.DataSource
Adding -Xextended-compiler-checks argument might provide additional information.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
//kotlin("jvm") version "1.6.0"
}
group = "com.jasin"
version = "0.0.1"
dependencies {
//api(files("libs/jdbc-stdext-2.0.jar"))
implementation("org.ktorm:ktorm-core:3.4.1")
implementation("org.ktorm:ktorm-support-mysql:3.4.1")
implementation("mysql:mysql-connector-java:8.0.25")
implementation("com.zaxxer:HikariCP:5.0.1")
implementation("org.slf4j:slf4j-api:1.7.36")
implementation("org.slf4j:slf4j-simple:1.7.36")
testImplementation(kotlin("test"))
}
tasks.test {
useJUnit()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "11"
}
If I uncomment the following line
//api(files("libs/jdbc-stdext-2.0.jar"))
I get the following type errors
module jdbc.stdext reads package javax.sql from both jdbc.stdext and java.sql
If I recomment this line and try to build again(without cleaning the project), it works. As soon as I clean the project the error reappears. What is exactly going on here and how can I fix this? Any help would be appreciated.
edit: I should add that this is a multi-module project and it wasn't till I tried to define module-info.java files in separate modules that this error appeared. But the error is specific to one module, the module that I use to access my database that uses connection pooling with hikaricp.
module-info.java file
module com.cobis.db {
requires kotlin.stdlib;
requires com.zaxxer.hikari;
requires ktorm.core;
exports com.cobis.db;
exports com.cobis.db.entities;
exports com.cobis.db.utilities;
}

Serialize kotlin data class in gradle's buildSrc/ during build

I'm looking to produce json files during the build cycle of my kotlin gradle app. My intent is to be able to instantiate data classes with a combination of public and private app configuration values that get put into the build's resources directory.
I'm looking at kotlinx.serialization, and I'd like to define these classes ideally in the projet's buildSrc/.
I haven't found any resources online for trying to setup serialization within gradle's build process, and not just configuring it for the app at runtime. This is what I've put together as my buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
kotlin("plugin.serialization") version "1.3.72"
}
repositories {
jcenter()
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")
}
And this is my test data class:
#Serializable
data class JsonGenerator(val x: String = "")
The error I get is:
Cannot access 'Serializable': it is internal in 'kotlin.io'
It seems that this error can happen when the dependency isn't properly declared. But I'm still unclear whether buildSrc has restrictions that make this impossible or not. I'm not married to this approach, but this seemed like the best solution.
Edit:
I've changed my buildSrc/build.gradle.kts to:
plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}
dependencies {
implementation(kotlin("serialization"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
}
Structure:
buildSrc
main
Kotlin
MyTempClass.kt
It is important for the kt file to not be nested, I think that will only work if the file is the same name as the nesting directory
Inside of my data class file:
import kotlinx.serialization.*
#Serializable
data class MyTempClass(val name: String)
I had a specific implementation of serialization, without the plugin.
Then in the top level build.gradle.kts, the MyTempClass was accessible

Unable to resolve cinterop IOS import in Kotlin Multiplatform

I have followed the Kotlin documentation for adding iOS dependencies. In my case the dependency is a pre-compiled framework provided through a third party. So I have followed the case for framework without cocoapod.
I placed my MyFramework.def file in /src
language = Objective-C
modules = MyFramework
package = MyFramework
Then I added the following to the build.gradle.kts in the Kotlin object
```
ios {
binaries {
framework {
baseName = "shared"
}
}
}
iosArm64() {
compilations.getByName("main") {
val JWBLe by cinterops.creating {
// Path to .def file
defFile("src/nativeInterop/cinterop/MyFramework.def")
compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
binaries.all {
// Tell the linker where the framework is located.
linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("com.google.android.material:material:1.2.1")
}
}
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13")
}
}
val iosMain by getting
val iosTest by getting
}
Then I build the project. The library does indeed get seen and I see that in External Libraries, there is a shared-cinterop-MyFramework.klib
However, when I try to import this package into my code under src/iosMain/kotlin/com.example.testapp.shared/platform.kt
I get unresolved error for the library. It seems like I should also need to add something to sourceSets? But I am unsure.
First of all, I got to notice that the Gradle script is incorrect. In this case, the iosArm64 target was declared twice - by the target shortcut and once again where you configure the cinterop. To avoid this duplication, it would be better to configure cinterop like that:
ios()
val iosArm = targets.getByName("iosArm64") as org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
// A bit dirty cast, but as I'm sure iosArm64 is the Native target, it should be fine. Needed to make highlighting below work as expected.
iosArm.apply {
compilations.getByName("main") {
val JWBLe by cinterops.creating {
// Path to .def file
defFile("src/nativeInterop/cinterop/MyFramework.def")
compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
binaries.all {
// Tell the linker where the framework is located.
linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
However, this adjustment won't help with accessing cinterop bindings from the iosMain. In the current state of commonizer, it can share only platform libraries. So anyway, moving all code utilizing those bindings into the src/iosArm64Main folder is the best option available at the moment. Here go an issue from the official tracker to upvote and subscribe - Support commonization of user-defined libraries.
So after some playing around I found the answer.
The dependency was set for a module of iosArm64 which is not available to the iosMain.
I created another folder src/iosArm64Main and placed the source file there. At that point it was able to resolve the library.

Setting up gradle and project structure for Kotlin Multiplatform project

I want to build a CLI tool with Kotlin Multiplatform which runs on Linux, Macos and Windows.
But I am struggling with setting up my build.gradle and my project structure. I am using IntelliJ IDEA 2020.1 and created my basic project with File -> New -> Project -> Kotlin / Native | Gradle
Currently I am looking through guides from kotlinlang.org but I am more falling then achieving something.
So far my build.gradle looks as follows:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.72'
}
repositories {
mavenCentral()
}
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
linuxX64("linux") {
}
mingwX64("mingw") {
}
macosX64("macos") {
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
sourceSets {
commonMain {
kotlin.srcDir('src/main')
resources.srcDir('src/res')
dependencies {
implementation kotlin('stdlib-common')
implementation "com.github.ajalt:clikt-multiplatform:2.7.0"
}
}
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
macosX64().compilations.test.defaultSourceSet {
dependsOn commonMain
}
// Note: To enable common source sets please comment out
'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
macosMain {
}
macosTest {
}
}
}
wrapper {
gradleVersion = "6.4.1"
distributionType = "ALL"
}
And my project structure is still basic:
Project structure
Formerly I only worked on Android Projects with Kotlin, and I guess I am spoiled with gradle as Android generates the most basic stuff and everything is working without doing that much.
I understand that I need to create packages like linuxMain and mingwMain, but where to I put common sourcesets? I tried to create a package called commonMain, but it won't even let me create Kotlin files in that package.
When I am finished I want to have (in the best case) one common source set and one entry point for all my targets. Is this even possible?
As far as I can see, you specify your commonMain source set's source locations as /src/main/. By default, it's usually set onto /src/commonMain/kotlin/. So if you will remove those srcDir settings and create a .kt file in your /src/commonMain/kotlin/ folder, everything should work fine. Also, I hope you have removed 'kotlin.import.noCommonSourceSets' property from your gradle.properties as your script recommended.

intellij idea 14 and gradle issues when running integTests

I have a gradle project imported into idea 14.0.3. The integration tests run fine from the command line. They were also running without any problems in idea 13 from the context menu (running single tests). However, in 14, when I use the context menu in IDE, for some reason the tests that depend on class path resources from src/integTest/resources are failing due to resource not being found. Any idea how I can add this folder in the classpath search in Intellij 14? Has anyone seen this issue before?
If I move the same resource to src/test/resources (or src/main/resources), the tests run fine. So it seems like intellij is not simply looking under src/integTest/resources.
Appreciate the help!!
I have run into this before as well, add the following to your build.gradle file:
// work-around to fix IDE-run test failures (may be fixed in future Gradle versions)
task copyMainResourcesToTest(type: Copy) {
from "${projectDir}/src/main/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyMainResourcesToTest
task copyTestResourcesToTest(type: Copy) {
from "${projectDir}/src/test/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyTestResourcesToTest
I think this may be resolved in the newest release of Gradle but I have not verified yet. You will want to update the paths for your specific use case.
Looks like this is Bug (IDEA-128966) in IntelliJ 14.
The recommended workaround is something like this:
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/integTest/resources')
}
if(System.properties.'idea.active') {
main {
resources.srcDir file('src/integTest/resources')
}
}
}
For our projects I changed that to:
if(System.properties.'idea.active') {
test { //Add to test rather than main
That still works and I think it communicates the intent better.
This workaround assumes you have configured your integration tests like this in the build.gradle:
apply plugin: 'idea'
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/inteTest/resources')
}
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
}
task integrationTest(type: Test, dependsOn: jar) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
build.dependsOn(integrationTest)
Note: This answer was originally deleted by a moderator because of a duplicate answer that I posted on another question. I now deleted my answer there (and added a link to here) because I think it fits this question better.