Skip to content

Instantly share code, notes, and snippets.

@jaumard
Created April 19, 2018 09:05
Show Gist options
  • Save jaumard/1fd1ccc9db0374cb5d08f047414a6bc8 to your computer and use it in GitHub Desktop.
Save jaumard/1fd1ccc9db0374cb5d08f047414a6bc8 to your computer and use it in GitHub Desktop.
Problem with kotlin generics
data class CustomerPersonalInfo(val memberNumber: String,
val name: String,
val surname: String,
val taxId: Int) {
private constructor(builder: Builder) : this(builder.memberNumber,
builder.name,
builder.surname,
builder.taxId)
class Builder {
var memberNumber: String = ""
private set
lateinit var name: String
private set
lateinit var surname: String
private set
var taxId = 0
private set
fun withMemberNumber(memberNumber: String) = apply { this.memberNumber = memberNumber }
fun withName(name: String) = apply { this.name = name }
fun withSurname(surname: String) = apply { this.surname = surname }
fun withTaxId(taxId: Int) = apply { this.taxId = taxId }
fun build() = CustomerPersonalInfo(this)
}
}
data class FormFieldDefinition(val fieldName: String)
class FormField<T>(var value: T, var name: String)
interface PersonalInfoFormFieldAccessor<T> {
private inline fun <reified T : Any> getGenericType() = T::class
fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<T>
fun setValueToBuilder(builder: CustomerPersonalInfo.Builder, value: T)
fun accept(visitor: PersonalInfoFormFieldVisitor)
fun getValueFromPersonalInfo(personalInfo: CustomerPersonalInfo): T
}
abstract class PersonalInfoFormFieldVisitor {
open fun visitString(accessor: PersonalInfoFormFieldAccessor<String>?) {
//to implement when override
}
open fun getString(accessor: PersonalInfoFormFieldAccessor<String>?): String {
return ""
}
open fun visitInt(personalInfoFormFieldAccessor: PersonalInfoFormFieldAccessor<Int>?) {
//to implement
}
}
class PersonalInfoFormFieldAccessors {
companion object {
const val FIRST_NAME = "firstName"
const val TAX_ID = "taxIdentificationNumber"
}
val accessors = mutableMapOf<String, PersonalInfoFormFieldAccessor<*>>()
init {
initAccessors()
}
private fun initAccessors() {
accessors[FIRST_NAME] = object : PersonalInfoFormFieldAccessor<String> {
override fun getValueFromPersonalInfo(personalInfo: CustomerPersonalInfo): String {
return personalInfo.surname
}
override fun accept(visitor: PersonalInfoFormFieldVisitor) {
visitor.visitString(this)
}
override fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<String> {
return FormField("test", FIRST_NAME)
}
override fun setValueToBuilder(builder: CustomerPersonalInfo.Builder, value: String) {
builder.withSurname(value)
}
}
accessors[TAX_ID] = object : PersonalInfoFormFieldAccessor<Int> {
override fun getValueFromPersonalInfo(personalInfo: CustomerPersonalInfo): Int {
return personalInfo.taxId
}
override fun accept(visitor: PersonalInfoFormFieldVisitor) {
visitor.visitInt(this)
}
override fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<Int> {
return FormField(1, TAX_ID)
}
override fun setValueToBuilder(builder: CustomerPersonalInfo.Builder, value: Int) {
builder.withTaxId(value)
}
}
}
}
class PersonalInfoFormDefinition(formFieldDefinitions: List<FormFieldDefinition>,
personalInfoAccessors: PersonalInfoFormFieldAccessors) {
private val fields: List<FormField<*>>
private val accessors = personalInfoAccessors.accessors
init {
fields = formFieldDefinitions.mapNotNull {
getFormField(it)
}.toList()
}
fun getFields(): List<FormField<*>> {
return fields
}
fun getPopulatedFields(personalInfo: CustomerPersonalInfo?): List<FormField<*>> {
return if (personalInfo == null) {
fields
} else {
fields.forEach { field ->
val fieldAccessor = accessors[field.name]
fieldAccessor?.accept(object : PersonalInfoFormFieldVisitor() {
override fun visitString(accessor: PersonalInfoFormFieldAccessor<String>?) {
field.value = accessor?.getValueFromPersonalInfo(personalInfo)
}
})
}
fields
}
}
fun getPersonalInfo(): CustomerPersonalInfo {
val builder = CustomerPersonalInfo.Builder()
for (field in fields) {
accessors[field.name]!!.setValueToBuilder(builder, field.value)
}
return builder.build()
}
private fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<*>? {
val fieldAccessor = accessors[formFieldDefinition.fieldName]
return fieldAccessor?.getFormField(formFieldDefinition)
}
}
fun main(args: Array<String>) {
//nothing to do
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment