Core extension functions that are dependency-free (mostly), things improving the JDK.
Module is available in artifacts:
- uy.kohesive.klutter:klutter-core
- uy.kohesive.klutter:klutter-core-jodatime
When initializing members or variables, these extensions allow you to encapsulate functionality with a nice label making the code more readable:
Further Initialization:
val myData = SomeDataClass() initializedBy {
it.addExtraData(123)
it.setRateName("fast")
}
or
val myData = SomeDataClass() initializedWith {
addExtraData(123)
setRateName("fast")
}
Verification before use:
val server = ServerConfigLoader(configFile) verifiedBy { loader ->
if (!loader.loggingDir.exists()) {
throw IllegalArgumentException("Invalid logging dir")
}
if (!loader.publicDir.exists()) {
throw IllegalArgumentException("Invalid public asset dir")
}
}
or verifiedWith
to operate directly on the instance as this
.
Turning an instance into a receiver (similar to with(instance) {}
but is instance.with {}
and can be used in an expression:
val userSet = getAllUsers().with {
addUser("Frank")
addUser("Gillian")
}.map { it.userId }.toSet()
Or when you want to execute code when something is not null, kinda the opposite of ?:
operator:
val byName: List<Company> = name.whenNotNull { companyService.findCompanyByName(name!!) }.whenNotNull { listOf(it) } ?: emptyList()
val byCountry: List<Company> = country.whenNotNull { companyService.findCompaniesByCountry(country!!) } ?: emptyList()
return (byName + byCountry).toSet()
or withNotNull
to operate directly on the instance as this
.
To all of the Number classes (Int, Long, Byte, Short, Double, ...)...
- minimum / maximum
- coerce
val threadCount = serverConfig.workerThreads.mimimum(8).maximum(64)
// or
val threadCount = serverConfig.workerThreads.coerce(8..64)
Note: these have since been added to Kotlin std runtime with different names. Keeping them for now, because the names here seem a bit more obvious.
Also available for Long and Int, humanReadable
:
println(1024.humanReadble()) // 1KB
fromEnd(N)
/fromStart(N)
- return the N number of characters at the start or endexceptEnding(N)
- return all but the last N charactersexceptLast()
- return all but the last 1 characterexceptStarting(N)
- return all after the first N charactersexceptFirst()
- return all after the first 1 charactermustStartWith(prefix)
- ensures the string starts with a given prefix, if it already does, do nothingmustEndWith(suffix)
- ensures the string ends with a given suffix, if it already does, do nothingmustNotStartWith(prefix)
- ensures the string does not start with a given prefix by removing it if it existsmustNotEndWith(suffix)
- ensures the string does not end with a given suffix by removing it if it existswhenStartsWith(prefix, lambda)
- run a block of code when a string starts with a prefix, passing in the remainder of the stringwhenStartsWith(prefixes, lamba)
- run a block of code when a string starts with any of a list of prefixes, passing in the remainder of the string with prefix removednullIfBlank()
- return null if the string is already null, empty, or only consists of white spacenullifEmpty()
- return null if the string is arleady null, or empty
The URLEncoder
/ URLDecoder
pairs in the JDK are not correct for the full standard, nor take into account new JavaScript %uXXXX encodings. Updated encoding methods for each type of item (path segment, query name/value, user info, ...) are provided. A universal decoder is also provided.
For encoding/decoding the UrlEncoding
singleton object contains these methods:
decode
- decode anything, including Javascript %uXXXX encoded charsencodeFragmentString
- encoding the part of the URL after the #encodeUserInfo
- encode the user auth info before the host nameencodePathParamName
- encode URL matrix parameter names in the pathencodePathParamValue
- encode URL matrix parameter values in the pathencodeQueryNameOrValue
- encode a query name or value, for the part after the ?encodeQueryNameOrValueNoParen
- same asencodeQueryNameOrValue
but strips parenthesisencodePathSegment
- encode a path segment (each part of the path between / slashes)
A UriBuilder
is provided that can be used to manipulate URL/URI in a safe encoded or decoded manner. The builder can return an ImmutableUri
, a Java URI
, or directly to a String.
The UriBuilder
has both properties and fluent methods. Any setting to an encoded value immediately is reflected in the matching decoded property. And vis versa.
UriBuilder
top-level helper functions returning UriBuilders
:
- buildUri(URI)
- buildUri(string)
- buildUri(URL)
- buildUri(ImmutableUri)
Some properties such as scheme
, host
, port
, userInfo
are somewhat self-evident. Other properties that are less so:
encodedPath
- the path encoded, if you split('/') you have encoded path segments (encoded byUrlEncoding.encodePathSegment
)decodedPath
- a List of already decoded path segmentsencodedFragment
- the fragment in its raw form (encoded withUrlEncoding.encodeFragmentString
)decodedFragment
- the fragment decoded as one stringencodedQuery
- the query string after the ? still encoded. If you split('&') you would have encoded query name=value pairs.decodedQuery
- the query string parsed, decoded and available as a multimap, with multiple values possible per parameter name.decodedQueryDeduped
- the query string parsed, decoded and deduped into a Map<String, String> with one value per parameter name.
Setting encodedPath
makes decodedPath
available automatically. And setting a list of strings to decodedPath
will encode them, and concatanate them into a encodedPath
string. This two way encode/decode is true for all property
pairs (or in the case of a query, setting one of the three, updates the others).
Since the Fragment can be used in many ways, there are helper methods for the encodedFragment
to be decoded other than as one string:
fragmentAsDecodedPath
- same asdecodedPath
but using fragment as the sourcefragmentAsDecodedQuery
- same asdecodedQuery
by using fragment as the sourcefragmentAsDecodedQueryDeduped
- same asdecodedQueryDeduped
by using fragment as the source
Other properties, fluent methods, hasXYZ() methods, clearXYZ() methods, and more can be seen by exploring the UriBuilder
class.
When an instance is full built, you can toString()
, toURI()
or build()
(as Immutable copy) the URI.
batch
- for Sequence and Iterable, batch a sequence into a sequence of lists of max N sizelazyBatch
- A purely Lazy batch must have the source consumed to progress, but does not need to materialize a list per iteration (is a combination of batch+forEach)
Kotlin collections have a read and write interface such as List
vs. MutableList
but these do not protect against write access since a simple cast back to the underlaying type can allow writing. Klutter adds lightweight delegating wrappers that block this write access for the collection, and any collection they return (such as iterator, listIterator, subList, etc).
*.asReadOnly()
- Wraps a Collection (extension functions exist for Iterator, Collection, List, ListIterator, Set, and Map) with a lightweight delegating class (low overhead) that prevents casting back to mutable type, all methods that return other collections (i.e. map.entries) are also wrapped with a protecting class*.toImmutable()
- copies the collection and then wraps it with the same as*.asReadOnly()
to prevent write access.
(based off of the answer from @miensol in this Stackoverflow answer http://stackoverflow.com/a/37936456/3679676)
ChildFirstClassloader
- a classloader that tries to load within the child classloader, before the parent. Adding a minimal level of isolation. Useful for dynamic loading ino a container.
Extension functions for:
- Path.exists()
- Path.notExists()
- Path.deleteRecursively() - Kotlin has File.deleteRecursively() but not for JDK 7 Path class
Top-level functions for:
- utcNow() - return current time as UTC Instant
- isoDateFormat() - return formatter for ISO date in the form
yyyy-MM-dd`T`hh:mm:ss.SSSZ
Extension functions for:
- Temporal.toIsoString() - convert any JDK 8 Date/Time class to ISO formatted string
yyyy-MM-dd`T`hh:mm:ss.SSSZ
Top-level functions for:
- utcNow() - return current time as UTC timezone Joda DateTime
- isoDateFormat() - return Joda DateTimeFormatter for ISO date in the form
yyyy-MM-dd`T`hh:mm:ss.SSSZ
Extension functions for:
- DateTime.toIsoString() - convert Joda DateTime class to ISO formatted string
yyyy-MM-dd`T`hh:mm:ss.SSSZ