Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import java.time.Duration
* fire-flush-await — making per-entry timing meaningless). Use
* [OutboxProcessorListener.onBatchProcessed] when you need batch-level timing.
*/
class OutboxProcessor(
class OutboxProcessor @JvmOverloads constructor(
private val store: OutboxStore,
private val entryProcessor: OutboxEntryProcessor,
private val listener: OutboxProcessorListener? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.softwaremill.okapi.core;

/**
* Java-side guard for {@code @JvmOverloads} on {@link OutboxProcessor}'s constructor.
*
* <p>These call sites compile only if {@code OutboxProcessor} exposes the shorter,
* default-omitting constructors to Java. Drop {@code @JvmOverloads} and okapi-core's test
* compilation fails right here — which is the point: a Kotlin-only test keeps compiling
* (Kotlin fills defaults at the call site) and would hide the regression. {@code
* OutboxProcessorJavaInteropTest} calls these so the guard also runs.
*/
public final class JavaOutboxProcessorConstruction {

private JavaOutboxProcessorConstruction() {}

/** {@code OutboxProcessor(store, entryProcessor)} — listener and clock default. */
public static OutboxProcessor withStoreAndProcessor(OutboxStore store, OutboxEntryProcessor entryProcessor) {
return new OutboxProcessor(store, entryProcessor);
}

/** {@code OutboxProcessor(store, entryProcessor, listener)} — clock defaults. */
public static OutboxProcessor withListener(
OutboxStore store, OutboxEntryProcessor entryProcessor, OutboxProcessorListener listener) {
return new OutboxProcessor(store, entryProcessor, listener);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.softwaremill.okapi.core

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import java.time.Clock
import java.time.Instant

/**
* Runs the Java call sites in [JavaOutboxProcessorConstruction], which compile only when
* [OutboxProcessor]'s constructor carries `@JvmOverloads`. The real guard is that Java source
* compiling — okapi-core has no other Java interop test, which is why the missing annotation
* regressed unnoticed. The stubs are inert: the constructor only stores its arguments.
*/
class OutboxProcessorJavaInteropTest :
FunSpec({
val store =
object : OutboxStore {
override fun persist(entry: OutboxEntry) = entry

override fun claimPending(limit: Int) = emptyList<OutboxEntry>()

override fun updateAfterProcessing(entry: OutboxEntry) = entry

override fun removeDeliveredBefore(time: Instant, limit: Int) = 0

override fun findOldestCreatedAt(statuses: Set<OutboxStatus>) = emptyMap<OutboxStatus, Instant>()

override fun countByStatuses() = emptyMap<OutboxStatus, Long>()
}
val entryProcessor =
OutboxEntryProcessor(
deliverer =
object : MessageDeliverer {
override val type = "stub"

override fun deliver(entry: OutboxEntry) = DeliveryResult.Success
},
retryPolicy = RetryPolicy(maxRetries = 3),
clock = Clock.systemUTC(),
)

test("Java can construct OutboxProcessor with trailing defaults omitted (@JvmOverloads)") {
JavaOutboxProcessorConstruction.withStoreAndProcessor(store, entryProcessor).shouldNotBeNull()
JavaOutboxProcessorConstruction.withListener(store, entryProcessor, null).shouldNotBeNull()
}
})