Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.39.1 breaks my application #1588

Closed
pindab0ter opened this issue Sep 5, 2022 · 6 comments
Closed

0.39.1 breaks my application #1588

pindab0ter opened this issue Sep 5, 2022 · 6 comments

Comments

@pindab0ter
Copy link

pindab0ter commented Sep 5, 2022

When updating from 0.38.2 to 0.39.1 or .2 my application breaks.

When I'm trying to load one or more instances of the Farmer DAO from the Farmers DSL, this error occurs:

transaction {
    Farmer.findById("1")
}
java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at kotlin.reflect.jvm.internal.calls.CallerImpl$Constructor.call(CallerImpl.kt:41)
	at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
	at org.jetbrains.exposed.dao.EntityClass$entityCtor$1.invoke(EntityClass.kt:32)
	at org.jetbrains.exposed.dao.EntityClass$entityCtor$1.invoke(EntityClass.kt:32)
	at org.jetbrains.exposed.dao.EntityClass.createInstance(EntityClass.kt:229)
	at org.jetbrains.exposed.dao.EntityClass.wrap(EntityClass.kt:233)
	at org.jetbrains.exposed.dao.EntityClass.wrapRow(EntityClass.kt:138)
	at org.jetbrains.exposed.dao.EntityClass$wrapRows$1.invoke(EntityClass.kt:125)
	at org.jetbrains.exposed.dao.EntityClass$wrapRows$1.invoke(EntityClass.kt:124)
	at org.jetbrains.exposed.sql.IterableExKt$mapLazy$1$iterator$1.next(IterableEx.kt:131)
	at kotlin.collections.CollectionsKt___CollectionsKt.firstOrNull(_Collections.kt:272)
	at org.jetbrains.exposed.dao.EntityClass.findById(EntityClass.kt:56)
	at org.jetbrains.exposed.dao.EntityClass.findById(EntityClass.kt:47)
	at nl.pindab0ter.eggbot.utilities.ScratchKt$main$2$1$1$1$result$1.invoke(Scratch.kt:24)
	at nl.pindab0ter.eggbot.utilities.ScratchKt$main$2$1$1$1$result$1.invoke(Scratch.kt:23)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction$run(ThreadLocalTransactionManager.kt:189)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.access$inTopLevelTransaction$run(ThreadLocalTransactionManager.kt:1)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$inTopLevelTransaction$1.invoke(ThreadLocalTransactionManager.kt:215)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.keepAndRestoreTransactionRefAfterRun(ThreadLocalTransactionManager.kt:223)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.inTopLevelTransaction(ThreadLocalTransactionManager.kt:214)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt$transaction$1.invoke(ThreadLocalTransactionManager.kt:165)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.keepAndRestoreTransactionRefAfterRun(ThreadLocalTransactionManager.kt:223)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.transaction(ThreadLocalTransactionManager.kt:135)
	at org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManagerKt.transaction(ThreadLocalTransactionManager.kt:132)
	at nl.pindab0ter.eggbot.utilities.ScratchKt$main$2$1$1.invokeSuspend(Scratch.kt:23)
	at nl.pindab0ter.eggbot.utilities.ScratchKt$main$2$1$1.invoke(Scratch.kt)
	at nl.pindab0ter.eggbot.utilities.ScratchKt$main$2$1$1.invoke(Scratch.kt)
	at com.kotlindiscord.kord.extensions.builders.ExtensibleBotBuilder$HooksBuilder.runBeforeExtensionsAdded(ExtensibleBotBuilder.kt:942)
	at com.kotlindiscord.kord.extensions.builders.ExtensibleBotBuilder.build$suspendImpl(ExtensibleBotBuilder.kt:478)
	at com.kotlindiscord.kord.extensions.builders.ExtensibleBotBuilder$build$1.invokeSuspend(ExtensibleBotBuilder.kt)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
	at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
	at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
	at kotlinx.coroutines.ResumeOnCompletion.invoke(JobSupport.kt:1398)
	at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1520)
	at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:323)
	at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:240)
	at kotlinx.coroutines.JobSupport.continueCompleting(JobSupport.kt:935)
	at kotlinx.coroutines.JobSupport.access$continueCompleting(JobSupport.kt:27)
	at kotlinx.coroutines.JobSupport$ChildCompletion.invoke(JobSupport.kt:1155)
	at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1520)
	at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:323)
	at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:240)
	at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:906)
	at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863)
	at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:828)
	at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
	at kotlinx.coroutines.debug.internal.DebugProbesImpl$CoroutineOwner.resumeWith(DebugProbesImpl.kt:545)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Caused by: java.lang.ExceptionInInitializerError
	at nl.pindab0ter.eggbot.model.database.Coop$Companion.<init>(Coop.kt:40)
	at nl.pindab0ter.eggbot.model.database.Coop$Companion.<init>(Coop.kt)
	at nl.pindab0ter.eggbot.model.database.Coop.<clinit>(Coop.kt:38)
	at nl.pindab0ter.eggbot.model.database.Farmer.<init>(Farmer.kt:30)
	... 65 more
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.text.StringsKt__StringsKt.substringAfter, parameter <this>
	at kotlin.text.StringsKt__StringsKt.substringAfter(Strings.kt)
	at kotlin.text.StringsKt__StringsKt.substringAfter$default(Strings.kt:456)
	at org.jetbrains.exposed.sql.Table.getTableNameWithoutScheme$exposed_core(Table.kt:334)
	at org.jetbrains.exposed.sql.Table$PrimaryKey.<init>(Table.kt:424)
	at org.jetbrains.exposed.dao.id.IntIdTable.<init>(IdTable.kt:43)
	at org.jetbrains.exposed.dao.id.IntIdTable.<init>(IdTable.kt:41)
	at nl.pindab0ter.eggbot.model.database.Coops.<init>(Coops.kt:8)
	at nl.pindab0ter.eggbot.model.database.Coops.<clinit>(Coops.kt)
	... 69 more

The error message doesn't tell me what went wrong specifically. It's not clear to me, at least.

Even though I'm not loading or using this relationship (no eager loading or calling it), it seems to originate in the Coops DSL, with the relation defined like this:

var coops by Coop via CoopFarmers

Unfortunately I can't open source the code. So please let me know what more details I should provide.

The error occurs even when the coops table is completely empty. No non-nullable fields in Farmer are null.

With 3.8.2 this worked without a problem.

@AlexeySoshin
Copy link
Contributor

Seems like Exposed is not able to figure out the name of the table from your table class.
Not sure why it only happens in 0.39, as this code wasn't changed in a year:

internal val tableNameWithoutScheme: String get() = tableName.substringAfter(".")

Can you please rename your Coop to CoopTable or try and specify the table explicitly?

@Tapac
Copy link
Contributor

Tapac commented Sep 7, 2022

@pindab0ter , can you share your Farmers table declaration and what Java version do you use?

@pindab0ter
Copy link
Author

pindab0ter commented Sep 28, 2022

Seems like Exposed is not able to figure out the name of the table from your table class. Not sure why it only happens in 0.39, as this code wasn't changed in a year:

internal val tableNameWithoutScheme: String get() = tableName.substringAfter(".")

Can you please rename your Coop to CoopTable or try and specify the table explicitly?

The table name was already explicitly defined:

object Coops : IntIdTable() {
    override val tableName = "coops"

@pindab0ter , can you share your Farmers table declaration and what Java version do you use?

The project uses Java version 11 (Azul Zulu 11.0.16, specifically), defined through kotlinOptions.jvmTarget and as the Project SDK in IntelliJ.

This is what Farmers.kt looks like:

import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.sql.ReferenceOption.CASCADE
import org.jetbrains.exposed.sql.jodatime.datetime
import org.joda.time.DateTime.now

object Farmers : IdTable<String>() {
    override val tableName = "farmers"
    override val id = text("id").entityId()
    override val primaryKey = PrimaryKey(id)
    val userId = reference("id", Users, CASCADE, CASCADE)
    // text, integer, double and long fields
    val createdAt = datetime("created_at").clientDefault { now() }
    val updatedAt = datetime("updated_at").clientDefault { now() }
}

I would like to reiterate that version 0.38.2 doesn't have this problem.

The earlier mentioned Coop and Farmer DAOs do have many-to-many relations defined:

// Farmer.kt (DAO)
// ...
    var coops by Coop via CoopFarmers
// ...

// Coop.kt (DAO)
// ...
    var farmers by Farmer via CoopFarmers
// ...

// CoopFarmers.kt (DSL)
object CoopFarmers : Table() {
    override val tableName = "coop_farmers"
    val farmer = reference("farmer", Farmers, CASCADE, CASCADE)
    val coop = reference("coop", Coops, CASCADE, CASCADE)

    init {
        index(true, farmer, coop)
    }
}

@Tapac
Copy link
Contributor

Tapac commented Sep 28, 2022

I was able to reproduce the bug, will fix it with next release.
As a workaround you can move table name into table declaration like:

object Farmers : IdTable<String>{"farmers") { ... }
object CoopFarmers : Table("coop_farmers")  { ... }

It should help

@pindab0ter
Copy link
Author

Awesome! Glad to hear you were able to reproduce the problem.

Thank you for providing a workaround as well. I will give that a go.

Do you want to leave this issue open until there’s a commit/PR/release with a fix, or should I close it?

@Tapac
Copy link
Contributor

Tapac commented Sep 28, 2022

I'll close it just after all tests will pass on CI.
The fix is on the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants