2017-06-15 34 views
5

我想在Kotlin编写一个Vaadin应用程序。对于数据绑定,Vaadin 8现在提供了类型安全数据绑定的可能性。在科特林我本来期望的工作像:类型推断失败:没有足够的信息来推断参数请指定它明确

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 }) 

    //... 
    } 
} 

我得到以下几条错误消息:

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. 

我试图通过显式指定类型参数:

binder.forField(name).bind<LoginView, String, LoginView>(
    { it.username }, 
    { bean, value -> bean.username = value }) 

但导致错误信息(和其他sytax错误,所以我没有按照该方法)

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 

我的第二个做法是试图直接通过科特林属性访问,但错误信息是一样的第一个:

binder.forField(name).bind(LoginModel::username.getter, LoginModel::username.setter) 

最后approeach试图用一个扩展方法,使一切,明确地:

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) 
} 

但它仍然会导致同样的错误消息作为第一个

回答

3

我曾尝试你的榜样,它编译我的IntelliJ 2017年1月4日和科特林1.1.2-5就好连接属性与给定名称inding。恐怕你已经发现了Kotlin插件旧版本中的一个bug。

该方法bind不采用通用参数,因此不能被基因化。该forField方法采用一个通用的参数,因此,或许你可以尝试

binder.forField<String>(name).bind(
      { it.username }, 
      { bean, value -> bean.username = value }) 

但首先,请确保您有科特林插件的最新版本,和/或可能尝试一下用的IntelliJ社区版。

但是,我强烈建议您使用bind(String),因为其他绑定方法不适用于JSR303验证。您也可以定义以下扩展方法:

fun <BEAN, FIELDVALUE> Binder.BindingBuilder<BEAN, FIELDVALUE>.bind(prop: KMutableProperty1<BEAN, FIELDVALUE?>): Binder.Binding<BEAN, FIELDVALUE> = 
     bind(prop.name) 

,并调用它从你的代码binder.forField(name).bind(LoginModel::username)如下。请参阅此处以获取更多示例:https://github.com/mvysny/karibu-dsl/blob/master/example-v8/src/main/kotlin/com/github/vok/karibudsl/example/form/FormView.kt

+0

我在Kotlin 1.1.2-5上也没有问题。 – petey

0

由于你的模型是相当简单的,你可以完成的b经由Binder#bind(String propertyName)方法

val binder = Binder<LoginModel>() 
binder.forField(name).bind("username"); 
+2

这将工作,但我想使用类型安全的数据绑定,并明白类型推断的问题是什么。 –

+1

这实际上是一个很好的建议,原因如下:如果您尝试将BeanValidationBinder与JSR-303验证一起用于“绑定(ValueProvider,Setter)”方法,它将跳过JSR-303验证!实际上您需要使用'bind(String)',以便可以从字段本身中挑选验证注释。 –

+0

@MartinVysny我同意。但是,OP想要做到kotlin风格。我可以欣赏这一点。 – petey

1

您必须使用API​​级别26+。这个版本改变了View的签名。findViewById() - 在这里看到https://developer.android.com/preview/api-overview.html#fvbi-signature

findViewById的结果是不明确的,你需要提供类型:

例如:

val myTextView = findViewById(R.id.list) as TextView 

成为

val myTextView = findViewById<TextView>(R.id.myTextView)