Kotlin error - There's a cycle in the delegation calls chain

Viewed 7249

I have a Kotlin data class which takes the parameters as below and parcelable. I have defined a secondary constructor within this data class with two additional parameters lastSeen and netTotal. But, I keep getting the error There's a cycle in the delegation calls chain for the secondary constructor. How do I resolve this?

@Parcelize
data class Person(
    val email: Email,
    val overrideEmail: Email,
    val phone: String,
    val firstName: String,
    val overrideFirstName: String,
    val lastName: String,
    val overrideLastName: String,
    val personId: String
) : Parcelable {

    //some code

    constructor(
    email: Email,
    overrideEmail: Email,
    phone: String,
    firstName: String,
    overrideFirstName: String,
    lastName: String,
    overrideLastName: String,
    personId: String,
    lastSeen: String,
    netTotal: Int?
) : this(email, overrideEmail, phone, firstName, overrideFirstName, lastName, overrideLastName, personId, lastSeen, netTotal)

}

Additionally I have to use this secondary constructor in a response mapper. The mapper with the original values are shown below. How would I include the secondary constructor in my response mapper?

class PersonFromResponseMapper @Inject constructor() : Mapper<Person, PersonResponse>() {
override fun map(from: PersonResponse, params: Any?): Person = with(from) {
    Person(
        Email(receiptEmailAddress.orEmpty()),
        Email(overrideEmail.orEmpty()),
        "",
        firstName.orEmpty(),
        overrideFirstName.orEmpty(),
        lastName.orEmpty(),
        overrideLastName.orEmpty(),
        personUserId.orEmpty()
    )
}
5 Answers

You get this error because you are calling the secondary constructor with your secondary constructor, thus making it a cycle. If you refactor/beautify your code a bit, then it becomes obvious:

// secondary constructor
constructor(
    email: Email,
    overrideEmail: Email,
    phone: String,
    firstName: String,
    overrideFirstName: String,
    lastName: String,
    overrideLastName: String,
    personId: String,
    lastSeen: String,
    netTotal: Int?
) : this(
    email, 
    overrideEmail, 
    phone, 
    firstName, 
    overrideFirstName, 
    lastName, 
    overrideLastName, 
    personId, 
    lastSeen, 
    netTotal
)

If you compare the arguments, you can see that you are calling the same (secondary) constructor. You have to call the primary constructor and use your additional parameters in the block afterwards.

If you fix that problem, you can also call your secondary constructor in your mapper, without any problems.

Try removing the last two arguments from the secondary constructor

@Parcelize
data class Person(
    val email: Email,
    val overrideEmail: Email,
    val phone: String,
    val firstName: String,
    val overrideFirstName: String,
    val lastName: String,
    val overrideLastName: String,
    val personId: String
) : Parcelable {

    //some code

    constructor(
    email: Email,
    overrideEmail: Email,
    phone: String,
    firstName: String,
    overrideFirstName: String,
    lastName: String,
    overrideLastName: String,
    personId: String,
    lastSeen: String,
    netTotal: Int?
) : this(email, overrideEmail, phone, firstName, overrideFirstName, lastName, overrideLastName, personId)

}
@Parcelize
data class Person(): Parceble{
var email: Email
var overrideEmail: Email
var phone: String
var firstName: String
var overrideFirstName: String
var lastName: String
var overrideLastName: String
var personId: String
var lastSeen: String
var netTotal: Int?

//First constructor
constructor(
email: Email,
overrideEmail: Email,
phone: String,
firstName: String,
overrideFirstName: String,
lastName: String,
overrideLastName: String,
personId: String
) : this(){
    this.email = email
    this.overrideEmail = overrideEmail
    this.phone = phone
    this.firstName = firstName
    this.overrideFirstName = overrideFirstName
    this.lastName = lastName
    this.overrideLastName = overrideLastName
    this.personId = personId
}

//second constructor
constructor(
email: Email,
overrideEmail: Email,
phone: String,
firstName: String,
overrideFirstName: String,
lastName: String,
overrideLastName: String,
personId: String,
lastSeen: String,
netTotal: Int?
) : this(){
    this.email = email
    this.overrideEmail = overrideEmail
    this.phone = phone
    this.firstName = firstName
    this.overrideFirstName = overrideFirstName
    this.lastName = lastName
    this.overrideLastName = overrideLastName
    this.personId = personId
    this.lastSeen = lastSeen
    this.netTotal = netTotal
}
}

It's because the parameters defined in your primary and secondary constructors are the same

In my case, I forgot to declare a Primary Constructor.

Somebody who might see this comment,
check if you declared a primary Constructor clearly and correctly.

Related