Skip to content

Instantly share code, notes, and snippets.

@stellingsimon
Created February 16, 2023 15:46
Show Gist options
  • Save stellingsimon/71b48700a0c42852ba51b9f802342406 to your computer and use it in GitHub Desktop.
Save stellingsimon/71b48700a0c42852ba51b9f802342406 to your computer and use it in GitHub Desktop.
import org.slf4j.Logger
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
/**
* Use as follows:
* ```
* class SomeClass {
* companion object {
* val LOGGER by companionLoggerProvider()
* }
* }
* ```
*
* The above is equivalent to
* ```
* class SomeClass {
* companion object {
* val LOGGER: Logger = LoggerFactory.getLogger(SomeClass::class.java)
* }
* }
* ```
* but eliminates the risk of accidentally using some other class inside the `LoggerFactory.getLogger()` call.
*/
fun loggerProvider() = LoggerProvider()
class LoggerProvider {
operator fun provideDelegate(thisRef: Any, prop: KProperty<*>): ReadOnlyProperty<Any, Logger> {
val thisKlass = thisRef::class
val loggerClazz = when {
thisKlass.isCompanion -> thisRef::class.companionedJavaClass()
else -> thisRef::class.java
}
val logger = LoggerFactory.getLogger(loggerClazz)
return ReadOnlyProperty<Any, Logger> { _, _ -> logger }
}
/**
* @return the class that contains the companion object
*/
private fun KClass<*>.companionedJavaClass(): Class<*> = this.java.declaringClass
}
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
class LoggerProviderTest {
@Test
fun `it should use parent class if called from a companion object to log`() {
// Act
val logger = ExampleClassWithCompanion.LOGGER // accessing the property triggers the property delegate provider
// Assert
assertThat(logger.name, equalTo(ExampleClassWithCompanion::class.java.name))
}
@Test
fun `it should use class to log`() {
// Act
val logger =
ExampleClassWithoutCompanion().logger // accessing the property triggers the property delegate provider
// Assert
assertThat(logger.name, equalTo(ExampleClassWithoutCompanion::class.java.name))
}
@Test
fun `it should use ExampleObject to log`() {
// Act
val logger = ExampleObject.logger // accessing the property triggers the property delegate provider
// Assert
assertThat(logger.name, equalTo(ExampleObject::class.java.name))
}
}
private class ExampleClassWithCompanion {
companion object {
val LOGGER by loggerProvider()
}
}
private class ExampleClassWithoutCompanion {
val logger by loggerProvider()
}
private object ExampleObject {
val logger by loggerProvider()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment