2017-06-15 52 views
5

Próbuję napisać aplikację Vaadin w Kotlin. W przypadku wiązania danych Vaadin 8 zapewnia teraz możliwość bezpiecznego wiązania danych typu. W Kotlin Liczyłam praca tak:Wnioskowanie o typ nie powiodło się: za mało informacji, aby odczytać parametr Proszę podać go jawnie

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

    //... 
    } 
} 

Dostaję następujący komunikat o błędzie tutaj:

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. 

próbowałem przez wyraźnych określając parametry Typ:

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

ale to prowadzi do komunikatu o błędzie (i innych błędów sytax, więc nie zastosowałem tego podejścia)

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 

Moje drugie podejście próbuje bezpośrednio przekazać udostępniające właściwości Kotlin, ale komunikat o błędzie był taki sam jak pierwszy:

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

Ostatni approeach próbował użyć metodę rozszerzenia i zrobić wszystko jak wyraźny, jak to możliwe:

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

Ale to nadal prowadzi do tego samego komunikatu o błędzie jako pierwsza

Odpowiedz

3

Próbowałem swój przykład i kompiluje dobrze z moim IntelliJ 2017.1.4 i Kotlin 1.1.2-5 Binder#bind(String propertyName). Prawdopodobnie znalazłeś błąd w starszej wersji wtyczki Kotlin?

Metoda bind nie pobiera żadnych ogólnych parametrów, więc nie można jej wygenerować. Metoda forField trwa jeden ogólny parametr, więc chyba można spróbować

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

Ale po pierwsze, upewnij się, że masz najnowszą wersję wtyczki Kotlin i/lub może go wypróbować z IntelliJ Community Edition.

Jednak zachęcam do korzystania z bind(String), ponieważ inne metody bindowania nie będą działać z walidacjami JSR303. Można również zdefiniować następującą metodę rozszerzenia:

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

i nazywają to jak wynika z kodu binder.forField(name).bind(LoginModel::username). Więcej przykładów można znaleźć tutaj: https://github.com/mvysny/karibu-dsl/blob/master/example-v8/src/main/kotlin/com/github/vok/karibudsl/example/form/FormView.kt

+0

Nie miałem również problemów z Kotlinem 1.1.2-5. – petey

0

Ponieważ model jest dość prosty, można wykonać b inding po podłączeniu do obiektu o podanej nazwie metodą

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

To będzie działać, ale chciałbym użyć bezpiecznego wiązania danych typu i zrozumieć, jaki jest dokładnie problem z wnioskiem o typ. –

+1

To jest naprawdę dobra rada, z następującego powodu: jeśli kiedykolwiek spróbujesz użyć BeanValidationBinder z walidacją JSR-303 za pomocą metody 'bind (ValueProvider, Setter)', to pominie ona walidację JSR-303! Właściwie musisz użyć 'bind (String)', aby adnotacje walidacyjne mogły zostać wybrane z samego pola. –

+0

@MartinVysny Zgadzam się. Jednak OP chce zrobić to w stylu kotlin. I mogę to docenić. – petey

1

Musisz używać poziomu API 26+. Ta wersja zmieniła sygnaturę widoku.findViewById() - zobacz tutaj https://developer.android.com/preview/api-overview.html#fvbi-signature

Wynik findViewById jest niejednoznaczna, musisz podać typ:

na przykład:

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

staje

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