arkivanov / Decompose

Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing (navigation) and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.)
https://arkivanov.github.io/Decompose
Apache License 2.0
2.07k stars 82 forks source link

NoClassDefFoundError: com/arkivanov/essenty/utils/internal/FreezingKt #479

Closed sdzshn3 closed 9 months ago

sdzshn3 commented 9 months ago

I'm using 2.1.0-compose-experimental-beta-01 version

Targetting Android, iOS and JVM/Desktop platforms

shared gradle

val commonMain by getting {
    dependencies {
        api(Deps.decompose)
        api(Deps.decomposeJetbrainsExtension)
    }
}

Here's the log:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at java.desktop/java.awt.EventQueue.invokeAndWait(Unknown Source)
    at java.desktop/java.awt.EventQueue.invokeAndWait(Unknown Source)
    at java.desktop/javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
    at MainKt.invokeOnAwtSync(Main.kt:39)
    at MainKt.main(Main.kt:15)
    at MainKt.main(Main.kt)
Caused by: java.lang.NoClassDefFoundError: com/arkivanov/essenty/utils/internal/FreezingKt
    at com.arkivanov.essenty.lifecycle.LifecycleRegistryImpl.<init>(LifecycleRegistryImpl.kt:10)
    at com.arkivanov.essenty.lifecycle.LifecycleRegistryKt.LifecycleRegistry(LifecycleRegistry.kt:23)
    at com.arkivanov.essenty.lifecycle.LifecycleRegistryKt.LifecycleRegistry(LifecycleRegistry.kt:15)
    at MainKt$main$rootComponent$1.invoke(Main.kt:16)
    at MainKt$main$rootComponent$1.invoke(Main.kt:15)
    at MainKt.invokeOnAwtSync$lambda$0(Main.kt:39)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
    at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.arkivanov.essenty.utils.internal.FreezingKt
    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)
    ... 19 more
arkivanov commented 9 months ago

Please see: https://github.com/arkivanov/Decompose/issues/464

sdzshn3 commented 9 months ago

No luck even after adding those flags in command line options.

arkivanov commented 9 months ago

It would be nice to have a reproducer. It really looks like an issue with your environment.

sdzshn3 commented 9 months ago

Sure. I'll create a sample project. If it works, obviously there is something wrong in my specific project (as i have added desktop target manually into a KMM project).

sdzshn3 commented 9 months ago

I trimmed down my project and made this as a reproducer for you.

https://github.com/sdzshn3/DecomposeRepro

arkivanov commented 9 months ago

Thanks! Are there any specific steps to produce? I have successfully launched the desktop app via ./gradlew :desktop:run once. Subsequent runs throw an error which looks unrelated to Decompose.

Caused by: org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (table setting already exists)
    at org.sqlite.core.DB.newSQLException(DB.java:1179)
    at org.sqlite.core.DB.newSQLException(DB.java:1190)
    at org.sqlite.core.DB.throwex(DB.java:1150)
    at org.sqlite.core.NativeDB.prepare_utf8(Native Method)
    at org.sqlite.core.NativeDB.prepare(NativeDB.java:126)
    at org.sqlite.core.DB.prepare(DB.java:264)
    at org.sqlite.core.CorePreparedStatement.<init>(CorePreparedStatement.java:46)
    at org.sqlite.jdbc3.JDBC3PreparedStatement.<init>(JDBC3PreparedStatement.java:32)
    at org.sqlite.jdbc4.JDBC4PreparedStatement.<init>(JDBC4PreparedStatement.java:25)
    at org.sqlite.jdbc4.JDBC4Connection.prepareStatement(JDBC4Connection.java:34)
    at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:226)
    at org.sqlite.jdbc3.JDBC3Connection.prepareStatement(JDBC3Connection.java:206)
    at app.cash.sqldelight.driver.jdbc.JdbcDriver.execute(JdbcDriver.kt:130)
    at app.cash.sqldelight.db.SqlDriver$DefaultImpls.execute$default(SqlDriver.kt:63)
    at com.omniwyse.smarttrackadmin.database.shared.SmartTrackAdminDatabaseImpl$Schema.create-0iQ1-z0(SmartTrackAdminDatabaseImpl.kt:30)
    at com.omniwyse.smarttrackadmin.database.shared.SmartTrackAdminDatabaseImpl$Schema.create(SmartTrackAdminDatabaseImpl.kt:25)
    at com.omniwyse.smarttrackadmin.core.data.local.SqlDriverFactoryKt.sqlDriverFactory(SqlDriverFactory.kt:10)
    at com.omniwyse.smarttrackadmin.di.AppModuleKt$appModule$1$1.invoke(AppModule.kt:20)
    at com.omniwyse.smarttrackadmin.di.AppModuleKt$appModule$1$1.invoke(AppModule.kt:20)
    at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:54)
    ... 34 more
arkivanov commented 9 months ago

As a workaround, changed the SQL statement to CREATE TABLE IF NOT EXISTS and the app starts fine every time.

malliaridis commented 9 months ago

I launched your project for desktop and it works fine for me too. For Android I had to upgrade to Kotlin 1.9.10 due to the Compose Compiler (1.5.3) compatibility. I also had to remove the signing configuration since the configuration was otherwise invalid.

I looked into your dependencies and versions and noticed the following:

And a personal recommendation, I would not use Koin or Hilt in combination with Decompose, it will overcomplicate your project.

JuBan1 commented 9 months ago

It is only when running the desktop app?

I've encountered the same runtime problem. Not with Decompose but with Ktor, and after removing Ktor something else took its place.

It's not a Decompose problem but instead a problem of how IntelliJ/Android Studio packages and runs the executable. Apparently it doesn't supply the correct class paths (?) in some cases. gradlew run works just fine, however. My workaround was to avoid the default run configuration created by IJ and use a custom gradle configuration that executes run instead.

I wasn't able to find a specific reason for why it happens. At first I thought it was because of a specific Android Studio version but I tested it on several machines with different results.

arkivanov commented 9 months ago

Thanks for all the useful information!

sdzshn3 commented 9 months ago

Ignore about Koin, Hilt and multiple compose dependencies.

Initially I started the project with just Android and iOS (with native UIs). But then started to migrate to a full KMP project slowly migrating from hilt in Android to koin in shared and jetpack compose from Android to jetbrains compose in shared.

You can already see i commented hilt implementation

Will remove hilt and Jetpack Compose eventually after migration.

sdzshn3 commented 9 months ago

And now regarding the actual issue,

It's only happening in desktop.

So far I tried running the desktop app by using the green triangle "Play icon” button in the main function of desktop.

But, now I just tried running by creating a custom configuration as @JuBan1 suggested. Now it's working.

And thanks for remaining version suggestions. Since the app was working well in Android and iOS, I was expecting it to work in Desktop automatically.

And I didn't upgrade to Kotlin 1.9.10 is because, in Android Studio that version plugin is not yet available.

Regarding the sql error, this is surprising... In Android and iOS, it's working just with CREATE TABLE. Any way, I'll change it to IF NOT EXISTS and it's more fail safe.

arkivanov commented 9 months ago

Thanks for the update! Closing the issue.