I'm trying to write a Vaadin application in Kotlin. For data binding, Vaadin 8 now provides a possibility for type safe data binding. In Kotlin I would have expected work like that:
class LoginModel {
var username: String = ""
var password: String = ""
}
class LoginView : FormLayout() {
val name = TextField("name")
val password = TextField("password")
val loginButton = Button("login")
init {
val binder = Binder<LoginModel>()
binder.forField(name).bind(
{ it.username },
{ bean, value -> bean.username = value })
//...
}
}
I'm getting the following error message here:
Error:(23, 31) Kotlin: Type inference failed: Not enough information to infer parameter BEAN in fun <BEAN : Any!, TARGET : Any!, BEAN : Any!> Binder.BindingBuilder<BEAN#1 (type parameter of bind), TARGET>.bind(p0: ((BEAN#1!) -> TARGET!)!, p1: ((BEAN#1!, TARGET!) -> Unit)!): Binder.Binding<BEAN#1!, TARGET!>!
Please specify it explicitly.
I tried by explicit specifying the type parameters:
binder.forField(name).bind<LoginView, String, LoginView>(
{ it.username },
{ bean, value -> bean.username = value })
but that leads to the error message (and other sytax errors, so I did not follow that approach)
Error:(23, 35) Kotlin: No type arguments expected for fun bind(p0: ValueProvider<LoginModel!, String!>!, p1: Setter<LoginModel!, String!>!): Binder.Binding<LoginModel!, String!>! defined in com.vaadin.data.Binder.BindingBuilder
My second approach was trying to pass the Kotlin property accessors directly, but the error message was the same as the first one:
binder.forField(name).bind(LoginModel::username.getter, LoginModel::username.setter)
The last approeach was trying to use an extension method and make everything as explicit as possible:
fun <BEAN, TARGET> Binder.BindingBuilder<BEAN, TARGET>.bind(property: KMutableProperty1<BEAN, TARGET>) {
fun set(bean: BEAN): TARGET = property.get(bean)
fun get(bean: BEAN, value: TARGET): Unit = property.set(bean, value)
this.bind(::set, ::get)
}
But it leads still to the same error message as the first one
I have tried your example and it compiles just fine with my Intellij 2017.1.4 and Kotlin 1.1.2-5. Probably you have discovered a bug in older version of a Kotlin plugin?
The method bind
takes no generic parameters so it cannot be generified. The forField
method takes one generic parameter, so perhaps you can try
binder.forField<String>(name).bind(
{ it.username },
{ bean, value -> bean.username = value })
But first, please make sure that you have the newest version of the Kotlin plugin, and/or perhaps try it out with Intellij Community Edition.
However, I urge you to use bind(String)
since other bind methods won't work with JSR303 validations. You can also define the following extension method:
fun <BEAN, FIELDVALUE> Binder.BindingBuilder<BEAN, FIELDVALUE>.bind(prop: KMutableProperty1<BEAN, FIELDVALUE?>): Binder.Binding<BEAN, FIELDVALUE> =
bind(prop.name)
And call it as follows from your code binder.forField(name).bind(LoginModel::username)
. Please see here for more examples: https://github.com/mvysny/karibu-dsl/blob/master/example-v8/src/main/kotlin/com/github/vok/karibudsl/example/form/FormView.kt
You must be using API level 26+. This version has changed the signature of View.findViewById() - see here https://developer.android.com/preview/api-overview.html#fvbi-signature
The result of findViewById is ambiguous, you need to supply the type:
For example:
val myTextView = findViewById(R.id.list) as TextView
becomes
val myTextView = findViewById<TextView>(R.id.myTextView)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With