Configurable factory in Kotlin for JavaScript - kotlin

I have a Kolin class A whose property is either supplied in a primary constructor, or is created by a factory in the secondary constructor of A.
interface I
class O : I
class A (val i: I) {
constructor(): this(factory!!.create())
}
interface Factory {
fun create(): I
}
class MyFactory: Factory {
override fun create(): I {
return O()
}
}
var factory: Factory? = null
fun main(args: Array<String>) {
factory = MyFactory()
A()
}
When I compile this code to JavaScript (Kolin Compiler version 1.0.6-release-127) and run it in a browser (Safari 10.0.3), I get the following runtime error:
ReferenceError:Can't find variable: tmp$0
The error occurs in the secondary constructor of A. It seems that Kolin has a problem in performing the null check of a parameter in the secondary constructor. The code runs correctly when I change the factory declaration to "not null" and remove the factory initialization from the main() method:
val factory: Factory = MyFactory()
fun main(args: Array<String>) {
A()
}
But this is not what I want, since I want to be able to configure the factory at application startup time.
Do I miss something, or is this a bug in Kotlin's JavaScript compiler? Does anybody know a workaround for this problem? Is there another or better way to design configurable factories in Kotlin for JavaScript?
Generated JavaScript code:
var KotlinTest = function (Kotlin) {
'use strict';
var _ = Kotlin.defineRootPackage(function () {
this.factory = null;
}, /** #lends _ */ {
I: Kotlin.createTrait(null),
O: Kotlin.createClass(function () {
return [_.I];
}, function O() {
}),
A: Kotlin.createClass(null, function A(i) {
this.i = i;
}),
A_init: function ($this) {
$this = $this || Object.create(_.A.prototype);
_.A.call($this, ((tmp$0 = _.factory) != null ? tmp$0 : Kotlin.throwNPE()).create());
return $this;
},
Factory: Kotlin.createTrait(null),
MyFactory: Kotlin.createClass(function () {
return [_.Factory];
}, function MyFactory() {
}, /** #lends _.MyFactory.prototype */ {
create: function () {
return new _.O();
}
}),
main_kand9s$: function (args) {
_.factory = new _.MyFactory();
_.A_init();
}
});
Kotlin.defineModule('KotlinTest', _);
_.main_kand9s$([]);
return _;
}(kotlin);

Answering my own question. As #marstran correctly commented, this seems to be a bug in Kolin's Javascript compiler 1.0.6 which seems to be fixed in 1.1-beta. In the meantime, I'm using a workaround similar to the following:
interface I
class O : I
class A (val i: I) {
constructor(): this(Factory.get().create())
}
interface Factory {
companion object {
private var IMPL : Factory? = null
fun get(): Factory = IMPL!!
fun set(impl: Factory) {
IMPL = impl
}
}
fun create(): I
}
class MyFactory: Factory {
override fun create(): I {
return O()
}
}
fun main(args: Array<String>) {
Factory.set(MyFactory())
A()
}

Related

How to mock extensions function in kotlin

I am using Mockk in my project. I am trying to mock my extension function but it cannot find my function. I tried some piece of code but it cannot find the extension function inside my test. Can someone guide me, How can I solve this issue. Thanks
ExploreConsultationsActivity.kt
class ExploreConsultationsActivity : AppCompactActvity () {
... // more function
internal fun setupExploreConsultationVisibility(hasFocus: Boolean) {
if (hasFocus) {
.....
} else if (viewModel.queryText.isEmpty()) {
binding.consultationViewSwitcher.displayConsultationViewSwitcherChild(0)
}
}
internal fun ViewSwitcher.displayConsultationViewSwitcherChild(childNumber: Int) {
visible()
displayedChild = childNumber
}
}
ExploreConsultationsActivityTest.kt
class ExploreConsultationsActivityTest {
#get:Rule
val testInstantTaskExecutorRule: TestRule = InstantTaskExecutorRule()
private val subject by lazy { spyk(ExploreConsultationsActivity()) }
#MockK private lateinit var mockConsultationViewSwitcher: ViewSwitcher
#Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)
setupMockView()
}
private fun setupMockView() {
mockkStatic(ExploreConsultationsLayoutBinding::class)
every { mockRootView.findViewById<ChipGroup>(R.id.exploreConsultationChips) } returns mockChipGroup
}
#Test
fun `setupExploreConsultationVisibility - `() {
// STUBBING
mockViewModel.queryText = ""
every { mockViewModel.topicSelected } returns ConsultationTopicsArea.ALL
with(mockConsultationViewSwitcher){
any<ViewSwitcher>().displayConsultationViewSwitcherChild(0)
}
// EXECUTION
subject.setupExploreConsultationVisibility(false)
// VERIFICATION
verify {
mockViewModel.filterBy(ConsultationTopicsArea.ALL)
}
}
I am getting this error

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()
}

Kotlin fallback wrapper

I'm looking for an elegant solution to the following.
I'd like to implement a Wrapper class that:
Accepts 2 implementations of the same Interface, and returns a new instance of that same Interface.
Any method call to the Wrapper object, tries to call the same method on the 1st implementation.
If the first call results into UnsupportedOperationException, then the 2th implementation should be used instead.
interface API {
fun getData(): String
}
class Main: API {
override fun getData(): String {
throw UnsupportedOperationException()
}
}
class Fallback: API {
override fun getData(): String {
return "data"
}
}
class Wrapper {
companion object {
fun getInstance(main: API, fallback: API): API {
// TODO
}
}
}
class Test {
#Test
fun `invokes the fallback instance`() {
val wrapper = Wrapper.getInstance(Main(), Fallback())
val response = wrapper.getData()
assertEquals(response, "data")
}
}
The best thing I have come up with so far is Delegate with Overrides:
class Wrapper(fallback: API): API by Main() {
val fallback = fallback
override fun getData(): String {
return fallback.getData()
}
}
What I don't like about this solution is that:
It requires overriding each unsupported operation
It gets quite verbose as the Interface grows into a complex multilevel structure with more sub interfaces
I'd also like to avoid Reflection for performance reasons and because this is a Kotlin Multiplatform project.
Any suggestions are appreciated.
Thanks,
Juan
Your proposed solution won't work because it will always favor the fallback for any overridden function.
There's no solution for your needs that can avoid having to manually handle every function of your interface. But you can have an intermediate function that handles the cascading selection of implementation for functions with the same signature.
class Wrapper (private val delegates: Array<out API>): API {
companion object {
fun getInstance(vararg delegates: API) = Wrapper(delegates)
}
private fun <R> delegate0Arg(function: API.() -> R): R {
for (delegate in delegates) {
try {
return delegate.function()
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override val name: String get() = delegate0Arg(API::name)
override fun getData(): String = delegate0Arg(API::getData)
}
But you would need additional functions to handle each unique number of arguments the interface functions have.
private fun <T, R> delegate1Arg(t: T, function: API.(t: T) -> R): R {
for (delegate in delegates) {
try {
return delegate.function(t)
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override fun getData(x: String) = delegate1Arg(x, API::getData)

Calling class in swift from kotlin/native framework

I followed the tutorial: https://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html and successfully export a jar file for Android and a framework for iOS. After I want to implement something more complex. I uses Android Studio Kotlin with the codes below:
Model.kt:
package org.kotlin.mpp.mobile.BusinessLogic
abstract class Model{
var _id:Long = 0
abstract fun PolymorphismTest()
}
Sales.kt:
package org.kotlin.mpp.mobile.BusinessLogic
class Sales : Model() {
init {
this._id = _counter
_counter++
}
companion object {
private var _counter: Long = 0
}
fun get_counter(): Long {
return _counter
}
private val _salesItems:MutableList<SalesItem> = ArrayList()
fun SalesItems(): MutableList<SalesItem> {
return _salesItems
}
fun TotalAmount():Double
{
var totalAmount:Double = 0.0
for(aSalesItem in _salesItems)
{
totalAmount += aSalesItem.SubTotal()
}
return totalAmount
}
fun AddSalesItem(salesItem: SalesItem)
{
this._salesItems.add(salesItem)
}
fun AddSalesItem(itemName:String, itemCode:String, quantity:Double, amount:Double )
{
val aSalesItem = SalesItem()
aSalesItem._itemCode = itemCode
aSalesItem._itemName = itemName
aSalesItem._quantity = quantity
aSalesItem._amount = amount
this.AddSalesItem(aSalesItem)
}
fun ToString(): String {
return "Sales: $this._id"
}
override fun PolymorphismTest() {
println("This is method from Sales")
}
}
SalesItem.kt:
package org.kotlin.mpp.mobile.BusinessLogic
class SalesItem : Model() {
init {
this._id = _counter
_counter++
}
companion object {
private var _counter: Long = 0
}
fun get_counter(): Long {
return _counter
}
var _sales: Sales? = null
var _amount:Double = 0.toDouble()
var _quantity:Double = 0.toDouble()
fun SubTotal(): Double {
return _amount * _quantity
}
var _itemName:String? = null
var _itemCode:String? = null
fun Sales():Sales?{
return _sales
}
fun SalesItem(sales:Sales)
{
_sales = sales
this._id = _counter
_counter++
}
fun ToString(): String {
return "Sales: $this._id"
}
override fun PolymorphismTest() {
println("This is method from SalesItem")
}
}
I export these codes into a framework then imported into Xcode and using Swift to call
ViewController.swift
import UIKit
import SharedCode
class ViewController: UIViewController{
override func viewDidLoad(){
super.viewDidLoad()
print("Creating Sales Object")
let sales = Sales() //error here
}
}
After that I met the errors of
Instances of kotlin.Error, kotlin.RuntimeException and subclasses aren't propagated from Kotlin to Objective-C/Swift.
Other exceptions can be propagated as NSError if method has or inherits #Throws annotation.
Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen org.kotlin.mpp.mobile.BusinessLogic.Sales.Companion#228b588
at 0 SharedCode
Kotlin/Native has different threading model. The idea is that an instance of an object has to be frozen to be accessed from all threads. There is .freeze() extension method for that.
By default, object Smth are also frozen. In the code sniper you have mutable fields in companion object.
A possible workaround could be to replace companion object with an ordinary class, that you create explicitly
https://kotlinlang.org/docs/reference/native/concurrency.html#concurrency-in-kotlinnative
https://kotlinlang.org/docs/reference/native/immutability.html#immutability-in-kotlinnative

cannot resolve reference to methods

I've got interfaces
interface IIMSIdentifiable {
fun setImsId(id : String)
fun getImsId() : String
}
interface IIMSConsumer : IIMSIdentifiable {
fun consumeAsync(message : GRLMessage)
}
And I've got a class that contains object with IIMSConsumer type
class IMSObject<IIMSConsumer> : Thread {
constructor(component : IIMSConsumer) {
obj = component
// IMSContext.instance.registerObject(this) // hm type mismatch
}
val objectMessageQueue = LinkedBlockingDeque<GRLMessage>()
val obj : IIMSConsumer
var isRunning = true
override fun run() {
while(isRunning) {
processMessages()
}
}
fun stopProcessing() {
isRunning = false
}
fun processMessages() {
objectMessageQueue.forEach {
obj.consumeAsync(it)
}
}
fun getObjectId() : String {
return obj.getImsId()
}
}
But it cannot resolve references
fun processMessages() {
objectMessageQueue.forEach {
obj.consumeAsync(it) // cannot resolve reference !!!
}
}
fun getObjectId() : String {
return obj.getImsId() // cannot resolve reference !!!
}
What is the problem? Oddly enought it did not ask for imports despite being located in different packages
com.lapots.game.journey.ims.domain.IMSObject
com.lapots.game.journey.ims.api.IIMSConsumer
I tried to test in on something simpler and get the same error with unresolved reference
interface IConsumer {
fun consume() : String
}
class Generic<IConsumer>(val consumer : IConsumer) {
fun invoke() {
print(consumer.consume()) // unresolved reference
}
}
fun main(args: Array<String>) {
val consumer = object : IConsumer {
override fun consume() : String {
return "I consume"
}
}
val generic = Generic<IConsumer>(consumer)
generic.invoke()
}
class Generic<IConsumer>(val consumer : IConsumer) {
You are creating a class Generic with a generic type parameter called IConsumer. This type parameter will shadow the interface you defined within that class, so you it actually says is:
class Generic<IConsumer : Any>(val consumer : Any) {
That is why it cannot resolve the method, since the generic parameter can only be interpreted as Any.
To fix either change the type parameter to have the appropriate names and bound (class Generic<T : IConsumer>(val consumer : T) {) or remove the generics entirely