如何解决Kotlin数据类属性映射过程中出现的StackOverflowError问题
问题根本原因
你在Kotlin属性的自定义getter实现中直接访问了属性本身,触发了无限递归调用getter方法,最终导致栈溢出。
两处具体错误点
contactPoints属性的get方法逻辑中,代码contactPoints.addresses = addressList会触发再次调用getContactPoints(),形成死循环,全程没有创建实际的ContactPoints实例,一直在递归调用getter。mainSubscriber属性的get方法存在完全相同的问题:mainSubscriber.firstName = givenName直接访问属性本身,再次触发getter调用,形成死循环。
修复方案
在自定义getter中先创建对应类的实例,对实例进行赋值操作后再返回实例,不要直接访问属性本身,修复后的UserInfoResponse对应代码如下:
data class UserInfoResponse( val id: String, val accountType: String, val alternatePhone: String, val alternatePhoneType: String, val billingCity: String, val billingCountry: String, val billingId: String, val billingPostalAddress1: String, val billingPostalAddress2: String, val billingPostalCode: String, val billingStateProvince: String, val currency: String, val effectiveRoles: List<EffectiveRole>, val givenName: String, val mailingCity: String, val mailingCountry: String, val mailingPostalAddress1: String, val mailingPostalAddress2: String, val mailingPostalCode: String, val mailingStateProvince: String, val primaryPhone: String, val primaryPhoneType: String, val secondaryPhone: String, val secondaryPhoneType: String, val suffix: String, val surname: String, val userName: String, val vehicles: List<Vehicle>, ) { val contactPoints: ContactPoints get() = run { // 先创建ContactPoints实例 val points = ContactPoints() var address = Address() val addressList = arrayListOf<Address>() address.id = id address.street = billingPostalAddress1 address.addressLine1 = billingPostalAddress1 address.city = billingCity address.state = billingStateProvince address.postalCode = billingPostalCode address.country = billingCountry addressList.add(address) address = Address() address.id = id address.street = mailingPostalAddress1 address.city = mailingCity address.state = mailingStateProvince address.postalCode = billingPostalCode address.country = mailingCountry addressList.add(address) // 对实例赋值而非直接访问属性 points.addresses = addressList var phone = Phone() val phoneList = arrayListOf<Phone>() phone.value = primaryPhone phoneList.add(phone) phone = Phone() phone.value = primaryPhone phoneList.add(phone) points.phones = phoneList // 返回实例 points } val mainSubscriber: MainSubscriber get() = run { // 先创建MainSubscriber实例 val subscriber = MainSubscriber() subscriber.firstName = givenName subscriber.lastName = surname subscriber.contactPoints = contactPoints // 返回实例 subscriber } }
可选优化
如果你不需要每次访问属性都重新生成新的实例,可以去掉自定义getter,直接在初始化时赋值,仅生成一次实例,性能更好:
val contactPoints: ContactPoints = run { // 逻辑和上面getter内的完全一致 } val mainSubscriber: MainSubscriber = run { // 逻辑和上面getter内的完全一致 }
内容的提问来源于stack exchange,提问作者Kushagra Kumar
相关产品推荐
相关产品推荐

