Skip to content
Bluetape4k docs1.11

Core Kotlin Library

Latest stable Based on Bluetape4k release 1.11.0

Backend modules repeatedly need the same low-level contracts: parameter validation with consistent exception types, byte-safe encoders, bounded collections, date/time helpers, and Kotlin-friendly adapters around Java or Apache Commons APIs. bluetape4k-core centralizes those primitives so higher modules do not invent slightly different versions.

Add core when application code or another library needs several of its foundational types. Prefer a focused JDK/Kotlin expression when it is already clear and complete; core is most valuable when it establishes a shared contract used across modules. Do not pull in core merely for one trivial alias without checking the dependency cost.

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k:bluetape4k-core")
}

The repository compiles with Java 21 and Kotlin 2.3. Core is an API dependency of several higher bluetape4k modules.

The module is a toolbox rather than one runtime subsystem. Its main families are support validation/extensions, codec encoders, collections bounded and paginated containers, range value types, concurrent helpers, functional adapters, time DSLs, and reflection/Apache Commons bridges.

Validation names encode failure semantics: new require* helpers reject caller input with IllegalArgumentException. Collection capacity is part of the type contract; for example, BoundedStack and RingBuffer retain only a bounded working set.

Read Core in the order boundaries move through an execution flow rather than alphabetically by API name.

Core boundary validation map

Design questionChapterContract to decide
Where should invalid caller input stop?Validation and invariantsException type, parameter name, non-null internal model
How should bytes cross a text boundary?Encoding and data boundariesCharset, URL-safe Base64/Hex, malformed input
In what order should the latest N values be retained?Bounded collectionsCapacity, eviction, stack/ring read order
Does a time query include its end?Time and rangesEndpoint inclusion, overlap, timezone
How much active and waiting work is allowed?Concurrency and lifecycleRejection, cancellation, close order
How do these contracts form one component?Practical Core recipesEnd-to-end tests and operational signals
import io.bluetape4k.codec.encodeBase64String
import io.bluetape4k.support.requireNotBlank
fun tokenFor(userId: String?): String {
val id = userId.requireNotBlank("userId")
return id.encodeBase64String()
}

requireNotBlank returns the validated value, so validation can stay inside an expression without a second null assertion.

TaskStart with
Validate nullable strings and caller argumentsio.bluetape4k.support.RequireSupport extensions
Encode Base64, Base58, Base62, Hex, or URL62io.bluetape4k.codec
Keep a bounded LIFO or circular windowBoundedStack, RingBuffer
Represent pages or lazy permutationsPaginatedList, permutation extensions
Express open/closed range endpointsio.bluetape4k.range types
Compose duration, period, temporal, or quarter operationsio.bluetape4k.time
Reduce work concurrently with explicit close semanticsConcurrentReducer
RequirementPreferDo not choose it when
Validate nullable input and keep using the same valuerequireNotNull, requireNotBlank, and requirePositiveNumber familiesYou are checking an internal invariant. These functions represent caller errors with IllegalArgumentException.
Retain recent values in LIFO orderBoundedStackUse RingBuffer when values must replay chronologically.
Retain the latest N values in insertion orderRingBufferUse BoundedStack when top/pop semantics matter.
Bound both concurrent asynchronous requests and their waiting queueConcurrentReducerA coroutine semaphore or mapParallel is more natural when only suspend-function concurrency needs a bound.
Close global resources in reverse order during JVM shutdownShutdownQueueClose directly when a request, bean, or component lifecycle ends earlier.

1. Validate at the boundary and keep internal types simple

Section titled “1. Validate at the boundary and keep internal types simple”
import io.bluetape4k.support.requireNotBlank
import io.bluetape4k.support.requirePositiveNumber
data class PageRequest(val cursor: String, val size: Int)
fun pageRequest(cursor: String?, size: Int): PageRequest =
PageRequest(
cursor = cursor.requireNotBlank("cursor"),
size = size.requirePositiveNumber("size"),
)

Each require* function returns its validated receiver, so downstream code needs neither another nullable branch nor !!. Match the parameter name to the public API so an operational error identifies the invalid input immediately.

2. Choose bounded-collection order deliberately

Section titled “2. Choose bounded-collection order deliberately”
val undo = BoundedStack<String>(maxSize = 3)
undo.pushAll("v1", "v2", "v3", "v4")
undo.toList() // [v4, v3, v2] — top to bottom
val recent = RingBuffer<String>(maxSize = 3)
recent.addAll("v1", "v2", "v3", "v4")
recent.toList() // [v2, v3, v4] — oldest to newest

Both types discard the oldest value after reaching capacity, but their read directions differ. BoundedStack.pop() removes the newest value; RingBuffer.drop(n) removes the oldest values. Both are process-local structures, not durable queues or distributed backpressure mechanisms.

3. Put an explicit capacity boundary in front of an asynchronous API

Section titled “3. Put an explicit capacity boundary in front of an asynchronous API”
import io.bluetape4k.concurrent.concurrentReducerOf
import java.util.concurrent.CompletionStage
fun <T> fetchBounded(
ids: List<String>,
fetchAsync: (String) -> CompletionStage<T>,
): List<T> = concurrentReducerOf<T>(
maxConcurrency = 8,
maxQueueSize = 64,
).use { reducer ->
ids.map { id -> reducer.add { fetchAsync(id) } }
.map { promise -> promise.join() }
}

When the queue is full or the reducer is closed, add does not throw directly at the call site. It returns a CompletableFuture completed with CapacityReachedException or RejectedExecutionException, respectively. Always observe the returned promise. close() cancels queued jobs, but it does not forcibly interrupt an external CompletionStage that is already running.

Validate at the public boundary and pass non-null values inward. Keep codecs at transport/storage boundaries instead of scattering encoding through domain logic. Choose bounded collections when unbounded growth would turn backpressure into an out-of-memory failure. Close lifecycle-owning concurrency helpers in use/try-finally blocks.

Core wraps or complements Kotlin stdlib, Java time/reflection/concurrency, Apache Commons, Eclipse Collections, and hashing utilities selected by the module build. Higher bluetape4k modules expose core types in their public APIs, so applications may receive core transitively; declare it directly when source code imports its API.

There is no global configuration file. Behavior is selected by constructor arguments and function parameters such as collection capacity, charset, range boundary, or timeout. Keep those values near the owning component rather than hiding them in unrelated global state.

Validation helpers throw IllegalArgumentException for invalid caller input. Codec decoders propagate malformed-input errors according to the underlying codec. Bounded collections reject invalid capacities during construction. ConcurrentReducer.close() cancels queued work and rejects submissions after closure; callers must decide whether cancellation is an expected shutdown path or an error.

SymptomCheck firstResponse
A validation error reports an unexpected valueWhether an earlier chain step transformed the receiver and whether the parameter name is correctValidate the original boundary value once, then transform it.
Recent items appear in reverse orderBoundedStack.toList() is newest-first while RingBuffer.toList() is oldest-firstDistinguish undo from history and select the matching type.
A ConcurrentReducer promise fails through CompletionExceptionWhether the cause is CapacityReachedException, a task error, or a null stageMap queue saturation to an overload policy such as retry/429 separately from task failure.
Producers keep submitting after shutdownWhether RejectedExecutionException in returned promises is ignoredObserve every future, stop producers, and only then close the reducer.
Resource shutdown order is wrongShutdownQueue closes in reverse registration order (LIFO)Register dependencies first and wrappers that use them afterward.

Most helpers are allocation-only and own no background service. Pay attention to utilities that wrap executors, queues, or large buffers. Bound capacities from workload evidence, expose close/shutdown in the owning service lifecycle, and avoid using reflection helpers on hot paths without measurement.

Tests are organized by package and contract. Useful anchors include BoundedStackTest, PaginatedListTest, codec tests, range tests, time tests, and ConcurrentReducer tests. Run the module suite with:

Terminal window
./gradlew :bluetape4k-core:test --no-configuration-cache

When adopting one helper, copy the smallest matching test pattern rather than treating the whole module as one integration surface.

No single workshop covers the entire toolbox. Higher-level repository examples exercise core transitively. For focused learning, start from the matching unit test and turn one assertion into a small runnable experiment.

The breadth of core means its APIs do not share one lifecycle or performance profile. Read the source and tests for the selected family. Encoding is not encryption, reflection helpers do not make inaccessible APIs stable, and bounded containers do not provide distributed backpressure.

These diagrams are loaded directly from README assets published with the 1.11.0 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.

Module Overview diagram

Release README: bluetape4k/core/README.md

Core Class Structure diagram

Release README: bluetape4k/core/README.md

Validation Chaining Flow diagram

Release README: bluetape4k/core/README.md