Skip to content

Commit

Permalink
Enable Kotlin's explicit API (#39)
Browse files Browse the repository at this point in the history
* Added extensions module

* Increased version to 1.6.0

* Minor cleanup

* Enabled explicit API

* Cleanup based on PR comments

* Moved to release 1.6.1

Co-authored-by: tvkanters <[email protected]>
Co-authored-by: Rijn Buve <[email protected]>
  • Loading branch information
3 people authored Feb 18, 2022
1 parent f871c14 commit c73d9fe
Show file tree
Hide file tree
Showing 32 changed files with 173 additions and 163 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,10 @@ Contributors: Timon Kanters, Jeroen Erik Jensen, Krzysztof Karczewski

## Release notes

### 1.6.1

* Enables explicit API, requiring stricter type and visibility definitions of our public APIs.

### 1.6.0

* Added extensions module, providing general-purpose extension functions that can make your code more concise and
Expand Down
2 changes: 1 addition & 1 deletion extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
</parent>

<artifactId>extensions</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ package com.tomtom.kotlin.extensions
* chain-calling constructs however, the `as` operator can easily lead to reduced readability. `let`
* helps with this, but adds boilerplate that distracts from the functional flow.
*/
inline fun <reified T> Any.cast(): T =
public inline fun <reified T> Any.cast(): T =
this as T

/**
Expand Down Expand Up @@ -95,5 +95,5 @@ inline fun <reified T> Any.cast(): T =
* chain-calling constructs however, the `as?` operator can easily lead to reduced readability.
* `let` helps with this, but adds boilerplate that distracts from the functional flow.
*/
inline fun <reified T> Any.safeCast(): T? =
public inline fun <reified T> Any.safeCast(): T? =
this as? T
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ package com.tomtom.kotlin.extensions
/**
* Checks whether the collection contains duplicated elements.
*/
fun Iterable<*>.containsDuplicates(): Boolean {
public fun Iterable<*>.containsDuplicates(): Boolean {
val elements = mutableSetOf<Any?>()
return any { !elements.add(it) }
}

/**
* Checks whether the collection contains no duplicated elements.
*/
fun Collection<*>.containsNoDuplicates(): Boolean = !containsDuplicates()
public fun Collection<*>.containsNoDuplicates(): Boolean = !containsDuplicates()
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ package com.tomtom.kotlin.extensions
* It may be inefficient to invert the logic to `someValue.takeIf { someCondition }` when
* `someValue` isn't readily available.
*/
inline fun <T> Boolean?.ifTrue(block: () -> T): T? =
public inline fun <T> Boolean?.ifTrue(block: () -> T): T? =
if (this == true) block() else null

/**
Expand Down Expand Up @@ -72,5 +72,5 @@ inline fun <T> Boolean?.ifTrue(block: () -> T): T? =
* chain-calling constructs however, the Elvis operator can easily lead to reduced readability.
* `let` helps with this, but adds boilerplate that distracts from the functional flow.
*/
inline fun <T> T?.ifNull(block: () -> T) : T =
public inline fun <T> T?.ifNull(block: () -> T) : T =
this ?: block()
2 changes: 1 addition & 1 deletion memoization/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
</parent>

<artifactId>memoization</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.tomtom.kotlin.memoization
* Creates a memoized function that caches result during first call and returns that value on subsequent calls.
* Important: Use with care, as the cache for this function is unbound. If function parameters
*/
fun <R> (() -> R).memoize(): () -> R =
public fun <R> (() -> R).memoize(): () -> R =
object : () -> R {
val result by lazy(LazyThreadSafetyMode.NONE) { this@memoize() }
override fun invoke(): R = result
Expand All @@ -28,13 +28,13 @@ fun <R> (() -> R).memoize(): () -> R =
/**
* Creates a LRU style cached function that will return cached result when the same input occurs again.
*/
fun <P1, R> ((P1) -> R).memoize(cacheSize: Int): (P1) -> R =
public fun <P1, R> ((P1) -> R).memoize(cacheSize: Int): (P1) -> R =
Function1Cache(this, cacheSize = cacheSize)

/**
* Creates a LRU style cached function that will return cached result when the same input occurs again.
*/
fun <P1, P2, R> ((P1, P2) -> R).memoize(cacheSize: Int): (P1, P2) -> R =
public fun <P1, P2, R> ((P1, P2) -> R).memoize(cacheSize: Int): (P1, P2) -> R =
object : (P1, P2) -> R {
private val cache = { pair: Pair<P1, P2> ->
this@memoize(pair.first, pair.second)
Expand All @@ -46,7 +46,7 @@ fun <P1, P2, R> ((P1, P2) -> R).memoize(cacheSize: Int): (P1, P2) -> R =
/**
* Creates a LRU style cached function that will return cached result when the same input occurs again.
*/
fun <P1, P2, P3, R> ((P1, P2, P3) -> R).memoize(cacheSize: Int): (P1, P2, P3) -> R =
public fun <P1, P2, P3, R> ((P1, P2, P3) -> R).memoize(cacheSize: Int): (P1, P2, P3) -> R =
object : (P1, P2, P3) -> R {
private val cache = { triple: Triple<P1, P2, P3> ->
this@memoize(triple.first, triple.second, triple.third)
Expand All @@ -58,7 +58,7 @@ fun <P1, P2, P3, R> ((P1, P2, P3) -> R).memoize(cacheSize: Int): (P1, P2, P3) ->
/**
* Creates a LRU style cached function that will return cached result when the same input occurs again.
*/
fun <P1, P2, P3, P4, R> ((P1, P2, P3, P4) -> R).memoize(cacheSize: Int): (P1, P2, P3, P4) -> R =
public fun <P1, P2, P3, P4, R> ((P1, P2, P3, P4) -> R).memoize(cacheSize: Int): (P1, P2, P3, P4) -> R =
object : (P1, P2, P3, P4) -> R {
private val cache = { quadruple: Quadruple<P1, P2, P3, P4> ->
this@memoize(quadruple.first, quadruple.second, quadruple.third, quadruple.fourth)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class FunctionMemoizationExtensionsTest {
internal class FunctionMemoizationExtensionsTest {
private var callCounter = 0
private val testString = "Test"

Expand Down
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
<packaging>pom</packaging>

<name>Kotlin Tools</name>
Expand Down Expand Up @@ -227,6 +227,12 @@
</goals>
</execution>
</executions>

<configuration>
<args>
<arg>-Xexplicit-api=strict</arg>
</args>
</configuration>
</plugin>

<plugin>
Expand Down
2 changes: 1 addition & 1 deletion traceevents/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
</parent>

<artifactId>traceevents</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ package com.tomtom.kotlin.traceevents
* more detailed explanation on how to use this class (and how to create specific trace event
* handlers as well).
*/
interface GenericTraceEventConsumer : TraceEventListener, TraceEventConsumer {
public interface GenericTraceEventConsumer : TraceEventListener, TraceEventConsumer {

/**
* The function [consumeTraceEvent] logs a trace event as type-safe objects (including the
* method name of the calling function).
*
* @param traceEvent Trace event.
*/
suspend fun consumeTraceEvent(traceEvent: TraceEvent)
public suspend fun consumeTraceEvent(traceEvent: TraceEvent)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import java.time.LocalDateTime
* `getNamedParametersMap` to access the parameters names and values. If `null` the map could not be created for some reason.
* You can still use the `args` array in that case.
*/
data class TraceEvent(
public data class TraceEvent(
val dateTime: LocalDateTime,
val logLevel: LogLevel,
val tracerClassName: String,
Expand All @@ -57,7 +57,7 @@ data class TraceEvent(
* Returns an empty map for parameterless methods and `null` if 1 or more parameter names are
* not available for some reason.
*/
fun getNamedParametersMap() =
public fun getNamedParametersMap(): Map<String, Any?>? =
parameterNames?.indices?.associateBy({ parameterNames[it] }, { args[it] })

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ package com.tomtom.kotlin.traceevents
* }
* ```
*/
interface TraceEventConsumer
public interface TraceEventConsumer
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import kotlin.reflect.full.valueParameters
import kotlin.reflect.jvm.javaMethod

/**
* This class registers event tracer consumer and finds (and caches) the functions in those
* consumer to call (by inspection) when events need to be handled.
* This class registers event tracer consumers and finds (and caches) the functions in those
* consumers to call (by inspection) when events need to be handled.
*/
class TraceEventConsumerCollection {
public class TraceEventConsumerCollection {

/**
* Add a trace event consumer, possibly for a specific context only (specified as a regex).
Expand All @@ -41,7 +41,7 @@ class TraceEventConsumerCollection {
* @param contextRegex If the regex matches the trace event context, the consumer will be called.
* If the regex is null, the consumer gets all events.
*/
fun add(traceEventConsumer: TraceEventConsumer, contextRegex: Regex?) {
public fun add(traceEventConsumer: TraceEventConsumer, contextRegex: Regex?) {
traceEventsConsumersWithContext.add(TraceEventConsumerWithContext(traceEventConsumer, contextRegex))
}

Expand All @@ -55,7 +55,7 @@ class TraceEventConsumerCollection {
* @param contextRegex Only the consumer for the given regex is removed. The consumer is removed
* for all contexts if the regex is null.
*/
fun remove(traceEventConsumer: TraceEventConsumer, contextRegex: Regex? = null) {
public fun remove(traceEventConsumer: TraceEventConsumer, contextRegex: Regex? = null) {
traceEventsConsumersWithContext.removeAll {
it.traceEventConsumer == traceEventConsumer &&
(contextRegex == null || it.contextRegex == contextRegex)
Expand All @@ -68,7 +68,7 @@ class TraceEventConsumerCollection {
*
* @param contextRegex Regex used when adding the consumer(s), or null to list all consumers.
*/
fun all(contextRegex: Regex? = null): Iterable<TraceEventConsumer> {
public fun all(contextRegex: Regex? = null): Iterable<TraceEventConsumer> {
return traceEventsConsumersWithContext.asIterable()
.filter { contextRegex == null || it.contextRegex == contextRegex }
.map { it.traceEventConsumer }
Expand All @@ -80,10 +80,9 @@ class TraceEventConsumerCollection {
*
* @param traceEvent Trace event to consume.
*/
suspend fun consumeTraceEvent(traceEvent: TraceEvent) {

public suspend fun consumeTraceEvent(traceEvent: TraceEvent) {
// Make sure we call each trace event consumer at most once.
var calledConsumers = mutableSetOf<TraceEventConsumer>();
val calledConsumers = mutableSetOf<TraceEventConsumer>()

// Trace events are offered to every handler that can handle the event.
for (traceEventConsumerWithContext in traceEventsConsumersWithContext) {
Expand All @@ -98,7 +97,7 @@ class TraceEventConsumerCollection {
traceEventConsumerWithContext.contextRegex == null ||
traceEventConsumerWithContext.contextRegex!!.matches(traceEvent.context)
) {
calledConsumers.add(traceEventConsumerWithContext.traceEventConsumer);
calledConsumers.add(traceEventConsumerWithContext.traceEventConsumer)
if (traceEventConsumerWithContext.traceEventConsumer is GenericTraceEventConsumer) {
traceEventConsumerWithContext.traceEventConsumer.consumeTraceEvent(traceEvent)
} else {
Expand Down Expand Up @@ -266,7 +265,7 @@ class TraceEventConsumerCollection {
*/
private val traceEventFunctions = HashMap<Key, Method>()

companion object {
private companion object {
val TAG = TraceEventConsumerCollection::class.simpleName!!
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,25 @@ package com.tomtom.kotlin.traceevents
* private val tracer = Tracer.Factory.create<TraceEventListener>(this)
* ...
* tracer.d("A debug message")
* ```
*/
interface TraceEventListener {
public interface TraceEventListener {

// Verbose
fun v(message: String, e: Throwable? = null) {}
public fun v(message: String, e: Throwable? = null) {}

// Debug
fun d(message: String, e: Throwable? = null) {}
public fun d(message: String, e: Throwable? = null) {}

// Info
fun i(message: String, e: Throwable? = null) {}
public fun i(message: String, e: Throwable? = null) {}

// Warn
fun w(message: String, e: Throwable? = null) {}
public fun w(message: String, e: Throwable? = null) {}

// Error
fun e(message: String, e: Throwable? = null) {}
public fun e(message: String, e: Throwable? = null) {}

// Called if an incorrect log function signature was used by a subclass.
fun incorrectLogSignatureFound() {}
public fun incorrectLogSignatureFound() {}
}
24 changes: 13 additions & 11 deletions traceevents/src/main/java/com/tomtom/kotlin/traceevents/TraceLog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,23 @@ import java.time.format.DateTimeFormatter
* This defines an interface [Logger], which may be implemented and injected using
* [setLogger] to modify the behavior of the simple text message loggers.
*/
interface TraceLog {
public interface TraceLog {

enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR }
public enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR }

/**
* Implement this interface for your own logger and set [log] accordingly.
*/
interface Logger {
fun log(logLevel: LogLevel, tag: String, message: String, e: Throwable? = null)
public interface Logger {
public fun log(logLevel: LogLevel, tag: String, message: String, e: Throwable? = null)
}

companion object {
public companion object {
/**
* Call this function if you need to use a different logger than the default
* implementation, which uses [println].
*/
fun setLogger(logger: Logger = DefaultLoggerToStdout) {
public fun setLogger(logger: Logger = DefaultLoggerToStdout) {
theLogger = logger
}

Expand All @@ -56,15 +56,17 @@ interface TraceLog {
*/
internal object DefaultLoggerToStdout : Logger {
override fun log(logLevel: LogLevel, tag: String, message: String, e: Throwable?) {
println("${createStdoutLogLine(logLevel, tag, message, e)}")
println(createStdoutLogLine(logLevel, tag, message, e))
}
}

internal fun createStdoutLogLine(
logLevel: LogLevel, tag: String, message: String, e: Throwable?
) =
"[${LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)}] $logLevel " +
"$tag: $message${e?.let { ", ${Tracer.formatThrowable(it, true)}" } ?: ""}"
logLevel: LogLevel,
tag: String,
message: String,
e: Throwable?
) = "[${LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)}] $logLevel " +
"$tag: $message${e?.let { ", ${Tracer.formatThrowable(it, true)}" } ?: ""}"

private var theLogger: Logger = DefaultLoggerToStdout
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ import com.tomtom.kotlin.traceevents.TraceLog.LogLevel
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
annotation class TraceLogLevel(val logLevel: LogLevel)
public annotation class TraceLogLevel(val logLevel: LogLevel)
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ package com.tomtom.kotlin.traceevents
* @param includeEventInterface Specifies whether the interface name of the [TraceEventListener]
* interface should be logged or not.
* Default is false.
*
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
annotation class TraceOptions(
public annotation class TraceOptions(
val includeExceptionStackTrace: Boolean = true,
val includeTaggingClass: Boolean = false,
val includeFileLocation: Boolean = false,
Expand Down
Loading

0 comments on commit c73d9fe

Please sign in to comment.