Inherit Companion Obejct in Children - Kotlin - kotlin

I've read that static methods cannot overridden in Kotlin, so I'm not sure if this is possible, but not being able to do so would result in a lot of repetitious code. Is there any way to achieve the same behavior while moving the companion object into the Parent? Here is what I have so far
Parent.kt
abstract class Parent {
protected val TAG = this::class.java.simpleName
}
Brother.kt
class Brother: Parent() {
companion object {
#Volatile private var instance: Brother? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: Brother().also { instance = it }
}
}
}
Sister.kt
class Sister: Parent() {
companion object {
#Volatile private var instance: Sister? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: Sister().also { instance = it }
}
}
}
main()
fun main() {
println("Hello, ${Brother.getInstance().TAG}")
println("Hello, ${Sister.getInstance().TAG}")
}
Console Output:
Hello, Brother Hello, Sister

Maybe this will work for what you're trying to do.
You can create a superclass for objects that do this pattern:
open class SingletonAccessor<T: Any> (private val constructor: () -> T){
#Volatile private var instance: T? = null
fun getInstance() = instance ?: synchronized(this) {
instance ?: constructor().also { instance = it }
}
}
And then inherit it from your implementation class companion objects:
class Brother private constructor(): Parent() {
companion object: SingletonAccessor<Brother>(::Brother)
}
class Sister private constructor(): Parent() {
companion object: SingletonAccessor<Sister>(::Sister)
}
This pattern isn't much different from simply making Brother and Sister objects, since they have no constructor parameters, but maybe this is just a simplified example.

Based on #Tenfour04's answer, I've come up with an alternate approach, which incorporates the SingletonAccessor into the Parent
abstract class Parent<T>(private val constructor: () -> T) {
#Volatile private var instance: T? = null
protected val TAG = this::class.java.simpleName
fun getInstance() = instance ?: synchronized(this) {
instance ?: constructor().also { instance = it }
}
}
The implementation in the children is the same as before.
Let me know if this answer can be improved further. In particular, I would like to do in the class declaration class Parent<T: Parent>, but that doesn't compile. Is there a way to limit the type parameter to itself and its children?

Related

Kotlin: Can I assign a function to a variable in a companion object from main?

New to kotlin, wondering if it's possible to dynamically assign
a function to a companion object's variable. Read the docs and some answers here but there's no mentioning about this.
class Printer {
companion object {
fun printAnything() {
println("printing anything..")
}
}
}
fun printA() {
println("printing A!")
}
fun main(args: Array<String>) {
printA()
Printer.printAnything = :: printA // doesn't compile, perhaps a different way?
}
You can't reassign a function that was declared with fun. It will always point to the same function. But you can make a var that holds a reference to a function. A var or val property holding a function can be invoked as a function, the same as if it was a fun declaration.
fun defaultPrintAnything() {
println("printing anything...")
}
var printAnything = ::defaultPrintAnything
fun printA() {
println("printing A!")
}
fun main() {
printAnything() // calls defaultPrintAnything
printAnything = ::printA
printAnything() // calls printA
}
You can make a variable like this anywhere you like, whether it's in a companion object or not. So yes, you can make your Printer companion object this way:
class Printer {
companion object {
var printAnything = {
println("printing anything..")
}
}
}

Mockk #OverrideMockKs not working with Kotest

I've using Kotest recently and I hadn't had any issues, but recently I was trying some annotations for dependency injection so to simplify the problem I created some basic classes with some methods that just print some messages, just for the sake of learning how to use Kotest and Mockk, but during the testing, I ran with the exception that the variable hasn't been initialized when trying to run the test.
These are my classes
class DefaultClass : AbstractClass() {
private val anotherClass: AnotherClass = AnotherClass()
fun testMethod(value: String): String {
val normalizeValue = value.trim().lowercase().replace(Regex("[^ A-Za-z\\d]*"), "")
return runBlocking {
anotherClass.someOtherMethod()
callsProtectedMethod(normalizeValue)
}
}
private suspend fun callsProtectedMethod(value: String) = coroutineScope {
println("Original method")
returnDefaultString(value)
}
}
AnotherClass
class AnotherClass {
fun someOtherMethod(): Unit {
println("SomeOtherMethod original")
}
}
Test
class DefaultClassTest : FunSpec({
context("Testing DefaultClass") {
#MockK
lateinit var anotherClass: AnotherClass
#OverrideMockKs
lateinit var defaultClass: DefaultClass
beforeContainer {
MockKAnnotations.init(this)
}
test("testing mocks") {
defaultClass.testMethod("some method")
}
}
I've changed the initialization to beforeTest, taken it out of the context, and also use beforeContainer, beforeTest, beforeSpec, but none of these work... every time I still get lateinit property defaultClass has not been initialized
So, I recreated the same test using JUnit and I don't have this issue.
class DefaultClassJUnitTest {
companion object {
#MockK
lateinit var anotherClass: AnotherClass
#OverrideMockKs
lateinit var defaultClass: DefaultClass
#BeforeAll
#JvmStatic
fun setup() {
MockKAnnotations.init(this)
}
}
#Test
fun `Testing with JUnit`() {
every { anotherClass.someOtherMethod() } answers {
println("Mocking another class")
}
val value = defaultClass.testMethod("some method")
}
}
So I'm pretty sure that I'm doing something wrong when using Kotest. I hope anyone might help me, thanks...
I think MockK is probably not looking for variables defined within function scopes. If you want to use the annotations, you likely have to move them to the companion object, like this:
class DefaultClassTest : FunSpec({
context("Testing DefaultClass") {
beforeContainer {
MockKAnnotations.init(this)
}
test("testing mocks") {
defaultClass.testMethod("some method")
}
}
}) {
companion object {
#MockK
lateinit var anotherClass: AnotherClass
#OverrideMockKs
lateinit var defaultClass: DefaultClass
}
}

How to use multi-generics in modules?

In java, i hava code like below:
public class GenericTest {
private static final GenericTest instance = new GenericTest();
IRequirement requirement;
public static GenericTest getInstance() {
return instance;
}
public class ClassA {}
public interface InterfaceA {}
public void init(IRequirement requirement){
this.requirement = requirement;
}
public interface IRequirement {
<T extends ClassA & InterfaceA> T supply();
}
class ClassB {
void doSomeThing() {
ClassA a = requirement.supply();
InterfaceA ia = requirement.supply();
}
}
}
I can get ClassA or InterfaceA instance according to my needs.
But in kotlin, same codes like below:
open class ClassA(val name: String) {
fun function1() {}
fun function2() {}
}
interface InterfaceA {
fun iFunction1()
}
class ModuleX private constructor() {
var requirement: IRequirement? = null
companion object {
val instance = ModuleX()
}
fun init(requirement: IRequirement) {
instance.requirement = requirement
}
interface IRequirement {
fun <T> supply(): T where T : ClassA, T : InterfaceA
}
}
object ClassB {
inline fun <reified T> doSomeThing() where T : ClassA, T : InterfaceA{
val require = ModuleX.instance.requirement?.supply<T>()
require?.function1()
require?.iFunction1()
}
fun doAnotherThing() {
// IDE give an error when calling supply()
val require = ModuleX.instance.requirement?.supply()
require?.function1()
require?.iFunction1()
}
}
I must specify the actual type of the generic, or use the generic method, otherwise I will not be able to use the IRequirement in the code above, such as in ClassB.doAnotherThing() where IDE give an error "Type inference failed: Not enough information to infer parameter T in fun supply( ): T where T : InterfaceAPlease specify it explicitly."
My question is: In my module, it is required to provide a class that extends ClassA and implements InterfaceAd, but the module does not know the exact type of the class because it is outside the module. How should I use generics in this case?
fun doAnotherThing() {
val require: Any? = ModuleX.instance.requirement?.supply()
if (require != null) {
(require as ClassA).function1()
(require as InterfaceA).iFunction1()
}
}

Generic types in class definitions and subclasses in Kotlin

I don't know the terminology of what I am trying to do, which makes asking the question difficult. Here is a minimal example:
abstract class Obj() {
abstract fun checkIssues() : List<String>
fun runRules(rules: List<Rule<Obj>>): List<String> {
return rules.mapNotNull {
it.check(this)
}
}
}
class Field(): Obj(){
companion object {
val rules = listOf(MissingResetRule())
}
override fun checkIssues(): List<String> = runRules(rules)
}
class MissingResetRule : Rule<Field>() {
override fun check(obj: Field): String? = ""
}
abstract class Rule<T: Obj> {
abstract fun check(obj: T): String?
}
The problem is that List<MissingResetRule> is not a subclass ofList<Rule<Obj>> or to be more precise, MissingRule is not a subclass of Rule<Obj>. This means runRules(rules) complains about the types being wrong. But Field is a subclass of Obj so I would have thought that Rule<Field> would be a subclass of Rule<Obj>. I can't seem to figure out how to tell the compiler that everything is valid here.
I have read the documentation here: https://kotlinlang.org/docs/reference/generics.html many times and can't understand how it applies to the code above.
As far as I understand your question, you try to have a function runRules that exactly get the rules of the corresponding type. Then make this function generic:
abstract class Obj() {
abstract fun checkIssues() : List<String>
}
fun <T : Obj> T.runRules(rules: List<Rule<T>>): List<String> {
return rules.mapNotNull {
it.check(this)
}
}
class Field(): Obj(){
companion object {
val rules = listOf(MissingResetRule())
}
override fun checkIssues(): List<String> = runRules(rules)
}
class MissingResetRule : Rule<Field>() {
override fun check(obj: Field): String? = ""
}
abstract class Rule<T: Obj> {
abstract fun check(obj: T): String?
}

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}