Can someone explain me why I cannot create empty secondary construcor in my class?
I wanna TEST it but I need to create a instance of class to use the methods from, but my class need a parametr to create it. I thought to create a scecondary constructor but when I'm trying it makes a error "There's a cycle in the delegation calls chain". Excatly I wanna use it on this #TEST below but when I'm trying to create instance of Adapter class I must put there also (FragmentManager) inside. Any ideas?
class Adapter(sFM: FragmentManager) : FragmentPagerAdapter(sFM, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
constructor() : this()
private val pFragmentList = ArrayList<Fragment>()
private val pFragmentTitle = ArrayList<String>()
override fun getCount(): Int = pFragmentList.size
override fun getItem(position: Int): Fragment = pFragmentList[position]
override fun getPageTitle(position: Int): CharSequence = pFragmentTitle[position]
fun addFragment(fm: Fragment, title: String) {
pFragmentList.add(fm)
pFragmentTitle.add(title)
}
}
#Test
fun `create instance of class Adapter`() {
var adapter = Adapter().addFragment()
}
There is no FragmentPagerAdapter with empty constructor. Basically, what your code is trying to compile, is to do constructor that calls itself. If you want to use base class constructor you need to use super instead of this. But still, you won't find such constructor in base class. You always have to pass some FragmentManager
Related
I want to dynamically implement an interface by extending an existing class as an anonymous object.
This anonymous object captures a method parameter to implement the interface method:
fun myFunc(someObj: SomeObj, update: Boolean) = object : SomeObj(/*copy some values from someObj*/), SomeInterface {
override fun doUpdate() = update
}
This implementation captures the update method parameter and adds it as a synthetic $update field into the anonymous object. I need to annotate this field as my serialization framework includes the $update field when its not marked as #Transient.
Another approach by delegation suffers from the same issue:
fun myFunc(someObj: SomeObj, update: Boolean) {
val someInterfaceImpl = object : SomeInterface {
override fun doUpdate() = update
}
return object : SomeObj(/*copy some values from someObj*/), SomeInterface by someInterfaceImpl
}
I cannnot annotate someInterfaceImpl in any place with #delegate:Transient or #Transient.
In essence:
Is there a way to annotate captured variables in Kotlin?
Is there a way to annotate the field when delegating to an object?
I am required to do this by annotations as the framework does not offer any other way to exclude fields, not even by names.
Furthermore I am not talking about delegated properties but delegated interfaces.
Create a named class:
fun myFunc(someObj: SomeObj, update: Boolean): SomeObj {
class SomeObjSubclass(someObj: SomeObj, #Transient val update: Boolean):
SomeObj(someObj.prop1, someObj.prop2, /* and so on*/), SomeInterface {
override fun doUpdate() = update
}
return SomeObjSubclass(someObj, update)
}
Notice that myFunc is now merely a wrapper for SomeObj. Depending on your design, you could just make myFunc the SomeObj subclass instead:
class MyFunc(someObj: SomeObj, #Transient val update: Boolean):
SomeObj(someObj.prop1, someObj.prop2, /* and so on*/), SomeInterface {
override fun doUpdate() = update
}
Callers would call MyFunc(...) as if it were a function, and they would receive something assignable to SomeObj, just like before.
You can also add a secondary constructor to SomeObj that takes a SomeObj, and copy the properties there
constructor(someObj: SomeObj): this(
someObj.prop1, someObj.prop2, /* and so on */
)
Then the declaration of MyFunc can just be:
class MyFunc(someObj: SomeObj, #Transient val update: Boolean):
SomeObj(someObj), SomeInterface {
override fun doUpdate() = update
}
I am having some issues with Mockito and stubbing out methods that uses a class as a parameter in Kotlin.
I have a few classes defined as follows:
open interface interfaceFile {
fun someFun(param1: String): String
}
abstact class abstractClass {
abstract val variable1: RandomType
open fun<T> getObject(param1: String, param2: Class<T>, vararg param3: Any): T? {
doSomeStuff()
}
open class concreteClass #Autowired constructor(
override val variable1: RandomType
): abstractClass(), interfaceFile {
override fun someFun(param1: String): String {
return getObject(param1, string::Class.java)!!
}
Then I tried to use mockito to mock the getObject function and test it as follows:
fun setUp() {
MockitoAnnotations.initMock(this)
testObject = mock(concreteClass::class.java)
}
fun testSomeFun() {
`when`(testObject!!.getObject("string1", String::class.java)).thenReturn("Mocked")
val actualResponse = testObject!!.someFun("string1")
assertEquals("message", "Mocked", actualResponse)
}
In short, concreteClass.someFun will call the abstractClass.getObject which will call doSomeStuff. But during testing I want to stub out abstractClass.getObject to just return. But the current behavior seems to be that I always get null instead.
I've simplified it to the point where it takes a single string parameter and stubbing it out then works, but seems when I introduce the class type as a parameter it stops working.
Search around it seems like my issue has to do with incorrect argument matching in my when call, but I can't figure out whats wrong with it since I even put in exact values instead of using ArgumentMatchers. Any suggestions would be greatly appreciated.
Your someFun method is from interface, so we can say it is open too. Thats why in mock it's overriding with returning null. To make it call basic code write following:
`when`(testObject!!.someFun("string1")).thenCallRealMethod()
By the way. Why your testObject is nullable? Set it lateinit var testObject: concreteClass to initialize it in setUp function.
I'm using kotlin android extensions to auto generate my Parcelables, but given the following code I'm getting 'Parcelable' should be a class.
the code:
sealed class Action : Parcelable
#Parcelize
object Run : Action()
#Parcelize
data class Ask(
val question: String
) : Action()
My understanding is that it is impossible to use #Parcelize in an object (Once it is working on the Ask class) in the way I'm doing it.
I want to use the Parcelable annotation in an object that extends a sealed class, so I'm do not know how to do it and do not write the following boilerplate.
object Run : Action() {
override fun writeToParcel(p0: Parcel?, p1: Int) {}
override fun describeContents() = 0
#JvmField
val CREATOR = object : Parcelable.Creator<Run> {
override fun createFromParcel(parcel: Parcel) = Run
override fun newArray(size: Int) = arrayOfNulls<Run?>(size)
}
}
You need to make sure that you have you Kotlin up to date.
You can follow an example here.
I'm trying to build a string with properties that are initialized in a subclass.
I read about lazy initialization but somehow this doesn't work as I expected.
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
private val packageName by lazy { packageName() }
private val processName by lazy { processName() }
val processFullName: String = "$moduleName/$packageName.$processName"
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
class WorkerFullNameBuilder(
private val jmsDirection: JmsDirectionEnumeration,
technicalDomain: TechnicalDomainEnumeration,
private val cdmCode: String) : SubProcessFullNameBuilder(technicalDomain) {
override fun packageName() = "$moduleName.workers.${jmsDirection.value().toLowerCase()}.${cdmCode.toLowerCase()}"
override fun processName() = "Worker"
}
Since I have overridden the packageName() and processName() properties, I would expect that on calling the packageName property it would use the implementation from the subclass.
But when I call the processFullName property, it throws a java.lang.NullPointerException.
val builder = WorkerFullNameBuilder(JmsDirectionEnumeration.ESB_IN, TechnicalDomainEnumeration.INFOR, "ccmd")
val name = builder.processFullName
How can I initialize the packageName and processName properties in a proper way?
This is a case of calling a non-final method in a constructor and thus accessing uninitialized variables.
This line is still evaluated eagerly, at the time when the base class is constructed:
val processFullName: String = "$moduleName/$packageName.$processName"
To get the values of the two lazy properties, this will make calls to the abstract methods, of which packageName() refers to jmsDirection and cdmCode to return its value - these properties are not initialized yet, because their values are set after the superclass constructor runs. Here's a simplified version of the subclass' constructor, decompiled back to Java:
public WorkerFullNameBuilder(#NotNull JmsDirectionEnumeration jmsDirection, #NotNull TechnicalDomainEnumeration technicalDomain, #NotNull String cdmCode) {
super(technicalDomain);
this.jmsDirection = jmsDirection;
this.cdmCode = cdmCode;
}
As a demonstration, if you don't refer to these, for example, if you return constants in both of the subclass methods, your code will actually run fine:
override fun packageName() = "foo"
override fun processName() = "Worker"
However, the solution you need here is most likely to make the processFullName property itself lazy instead of the two values it uses (which you're evaluating at constructor time right now anyway, so you're not making use of them being lazy). This means you don't even need those two as separate properties:
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
val processFullName by lazy { "$moduleName/${packageName()}.${processName()}" }
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
With given kotlin code :
sealed class Event(val id:String= UUID.randomUUID().toString(), val timestamp:Instant = Instant.now())
data class BarEvent(val additionalInfo:String):Event()
object FooEvent:Event()
// data class CorrectFooEvent():Event() // invalid kotlin
fun main(args: Array<String>) {
val b1 = BarEvent("b1")
val f1 = FooEvent
Thread.sleep(1000)
val b2 = BarEvent("b2")
val f2 = FooEvent
println("${b1.id} ${b1.timestamp} $b1")
println("${f1.id} ${f1.timestamp} $f1")
println("${b2.id} ${b2.timestamp} $b2")
println("${f2.id} ${f2.timestamp} $f2")
}
There is no issue with BarEvent.
But as FooEvent has no more parameter than the ones in Event, I would like it to have empty constructor. It's not authorized for data class, so I made it an object. But object is singleton, so it doesn't behave as an instanciated event.
The only workaround that I see (keeping the class as a data class) is something like :
sealed class Event(open val id:String= UUID.randomUUID().toString(), open val timestamp:Instant = Instant.now())
data class FooEvent(override val id:String= UUID.randomUUID().toString(), override val timestamp:Instant = Instant.now()):Event()
But it's not very elegant.
Just change FooEvent to a normal class, and add (or generate them using your IDE) toString(), hashCode() and equals(Object) if needed:
class FooEvent: Event() {
override hashCode() = ...
override equals(other: Object) {
...
}
override toString() = ...
}
To make the event a data class, simply add an unused property to it. Not pretty, but as short as it can be in Kotlin at the moment:
data class FooEvent(val dummy: Unit = Unit) : Event()
There seems to be no intention to remove this limitation soon:
Data class without arguments deprecated in 1.0. Why?
Suggestion for parameterless data class