gpt4 book ai didi

java - Vaadin 8 `Binder::bindInstanceFields` 是否仅适用于 String 数据类型?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:22:07 28 4
gpt4 key购买 nike

使用 Vaadin 8 @PropertyId带有 Binder::bindInstanceFields 的注释肯定比为每个字段属性绑定(bind)编写一行代码更短、更甜美。

Person person;  // `name` is String, `yearOfBirth` is Integer.

@PropertyId ( "name" )
final TextField nameField = new TextField ( "Full name:" ); // Bean property.

@PropertyId ( "yearOfBirth" )
final TextField yearOfBirthField = new TextField ( "Year of Birth:" ); // Bean property.

// Binding
Binder < Person > binder = new Binder <> ( Person.class );
binder.bindInstanceFields ( this );
binder.setBean ( person );

但我们会抛出异常,因为 yearOfBirth 属性是一个整数,而且这种简单易行的绑定(bind)方法缺少转换器。

SEVERE:

java.lang.IllegalStateException: Property type 'java.lang.Integer' doesn't match the field type 'java.lang.String'. Binding should be configured manually using converter.

这是否意味着 Binder::bindInstanceFields只能使用完全由 String 数据类型的属性组成的 bean 吗?

有没有办法指定一个 Converter例如StringToIntegerConverter无需逐条列出代码中的每个绑定(bind)?

最佳答案

参见 Vaadin Framework, Vaadin Data Model, Binding Data to Forms :

Conversions

You can also bind application data to a UI field component even though the types do not match.

Binder#bindInstanceFields() 说:

It's not always possible to bind a field to a property because their types are incompatible. E.g. custom converter is required to bind HasValue<String> and Integer property (that would be a case of "age" property). In such case IllegalStateException will be thrown unless the field has been configured manually before calling the bindInstanceFields(Object) method.

[...]: the bindInstanceFields(Object) method doesn't override existing bindings.

[我强调的。]

所以,AFAIU,这应该有效:

private final TextField siblingsCount = new TextField( "№ of Siblings" );

...

binder.forField( siblingsCount )
.withNullRepresentation( "" )
.withConverter(
new StringToIntegerConverter( Integer.valueOf( 0 ), "integers only" ) )
.bind( Child::getSiblingsCount, Child::setSiblingsCount );
binder.bindInstanceFields( this );

但它仍然抛出:

java.lang.IllegalStateException: Property type 'java.lang.Integer' doesn't match the field type 'java.lang.String'. Binding should be configured manually using converter.
...
at com.vaadin.data.Binder.bindInstanceFields(Binder.java:2135)
...

你在开玩笑吗?我就是这么做的,不是吗?我相当怀疑“没有覆盖现有绑定(bind)”。 或者,如果没有实际覆盖,它们似乎在 bindInstanceFields() 中被忽略了。 ,至少。

不使用 Binder#bindInstanceFields() 时,相同的手动绑定(bind)配置也有效但是每个字段都有单独绑定(bind)的方法。

另请参阅线程 Binding from Integer not working在 Vaadin 框架数据绑定(bind)论坛和 issue #8858 Binder.bindInstanceFields() overwrites existing bindings .

解决方法

比@cfrick 的回答更简单:

/** Used for workaround for Vaadin issue #8858
* 'Binder.bindInstanceFields() overwrites existing bindings'
* https://github.com/vaadin/framework/issues/8858
*/
private final Map<String, Component> manualBoundComponents = new HashMap<>();
...
// Commented here and declared local below for workaround for Vaadin issue #8858
//private final TextField siblingsCount = new TextField( "№ of Siblings" );
...

public ChildView() {
...

// Workaround for Vaadin issue #8858
// Declared local here to prevent processing by Binder#bindInstanceFields()
final TextField siblingsCount = new TextField( "№ of Siblings" );
manualBoundComponents.put( "siblingsCount", siblingsCount );
binder.forField( siblingsCount )
.withNullRepresentation( "" )
.withConverter( new StringToIntegerConverter( Integer.valueOf( 0 ), "integers only" ) )
.bind( Child::getSiblingsCount, Child::setSiblingsCount );
binder.bindInstanceFields( this );

...

// Workaround for Vaadin issue #8858
addComponent( manualBoundComponents.get( "siblingsCount" ) );
//addComponent( siblingsCount );

...
}

更新

Fix #8998 Make bindInstanceFields not bind fields already bound using functions .

source code for that fix至少出现在 Vaadin 8.1.0 alpha 4 pre-release 中(也许还有其他人)。


Basil Bourque 更新...

如上所示,您的想法是使用 Binder::bindInstanceFields在对不兼容(整数)属性进行手动绑定(bind)之后,确实对我有用。您提示在您的实验代码中调用了 Binder::bindInstanceFields未能遵循调用“不覆盖现有绑定(bind)”的记录行为。

但它似乎对我有用。这是 Vaadin 8.1.0 alpha 3 的示例应用程序。首先我手动绑定(bind) yearOfBirth属性(property)。然后我使用 binder.bindInstanceFields绑定(bind) @PropertyId注释 name属性(property)。这两个属性的字段显示已填充并响应用户编辑。

我是否遗漏了什么,或者它是否按照记录正常工作?如果我犯了错误,请删除此部分。

package com.example.vaadin.ex_formatinteger;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Binder;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.*;

import javax.servlet.annotation.WebServlet;

/**
* This UI is the application entry point. A UI may either represent a browser window
* (or tab) or some part of a html page where a Vaadin application is embedded.
* <p>
* The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be
* overridden to add component to the user interface and initialize non-component functionality.
*/
@Theme ( "mytheme" )
public class MyUI extends UI {
Person person;

//@PropertyId ( "honorific" )
final TextField honorific = new TextField ( "Honorific:" ); // Bean property.

//@PropertyId ( "name" )
final TextField name = new TextField ( "Full name:" ); // Bean property.

// Manually bind property to field.
final TextField yearOfBirthField = new TextField ( "Year of Birth:" ); // Bean property.

final Label spillTheBeanLabel = new Label ( ); // Debug. Not a property.

@Override
protected void init ( VaadinRequest vaadinRequest ) {
this.person = new Person ( "Ms.", "Margaret Hamilton", Integer.valueOf ( 1936 ) );

Button button = new Button ( "Spill" );
button.addClickListener ( ( Button.ClickEvent e ) -> {
spillTheBeanLabel.setValue ( person.toString ( ) );
} );

// Binding
Binder < Person > binder = new Binder <> ( Person.class );
binder.forField ( this.yearOfBirthField )
.withNullRepresentation ( "" )
.withConverter ( new StringToIntegerConverter ( Integer.valueOf ( 0 ), "integers only" ) )
.bind ( Person:: getYearOfBirth, Person:: setYearOfBirth );
binder.bindInstanceFields ( this );
binder.setBean ( person );


setContent ( new VerticalLayout ( honorific, name, yearOfBirthField, button, spillTheBeanLabel ) );
}

@WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
@VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
public static class MyUIServlet extends VaadinServlet {
}
}

而且简单Person类。

package com.example.vaadin.ex_formatinteger;

import java.time.LocalDate;
import java.time.ZoneId;

/**
* Created by Basil Bourque on 2017-03-31.
*/
public class Person {

private String honorific ;
private String name;
private Integer yearOfBirth;

// Constructor
public Person ( String honorificArg , String nameArg , Integer yearOfBirthArg ) {
this.honorific = honorificArg;
this.name = nameArg;
this.yearOfBirth = yearOfBirthArg;
}

public String getHonorific ( ) {
return honorific;
}

public void setHonorific ( String honorific ) {
this.honorific = honorific;
}

// name property
public String getName ( ) {
return name;
}

public void setName ( String nameArg ) {
this.name = nameArg;
}

// yearOfBirth property
public Integer getYearOfBirth ( ) {
return yearOfBirth;
}

public void setYearOfBirth ( Integer yearOfBirth ) {
this.yearOfBirth = yearOfBirth;
}

// age property. Calculated, so getter only, no setter.
public Integer getAge ( ) {
int age = ( LocalDate.now ( ZoneId.systemDefault ( ) )
.getYear ( ) - this.yearOfBirth );
return age;
}

@Override
public String toString ( ) {
return "Person{ " +
"honorific='" + this.getHonorific () + '\'' +
", name='" + this.getName () +
", yearOfBirth=" + this.yearOfBirth +
", age=" + this.getAge () +
" }";
}
}

关于java - Vaadin 8 `Binder::bindInstanceFields` 是否仅适用于 String 数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43154002/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com