通过定义一对 SerializableFunction 对象为数据绑定提供转换器

Provide a Converter for data-binding by defining a pair of SerializableFunction objects

在 Vaadin 8 Framework 和 Vaadin 10 Flow 中,数据绑定功能允许我们提供一个 Converter 来调解小部件的预期数据类型(例如 StringTextField) 和 backing bean 的数据类型 属性 (例如 Integer number).

在此示例中,使用内置 Converter 实现 StringToIntegerConverter

binder
.forField( this.phaseField )
.withConverter( 
    new StringToIntegerConverter( "Must enter an integer number" ) 
)
.bind( Panel::getPhase , Panel::setPhase ) ;

但是为其他类型定义一个 Converter 呢?如何轻松定义一个简短而甜蜜的Converter?例如,一个 String-to-UUID converter. I want to show the canonical 36-character hex string in a TextField, and going the other direction, parse that string back into a UUID.

// String to UUID
UUID uuid = UUID.fromString( myString ) ;

// UUID to String
String myString = uuid.toString() ;

我看到 Binder.BindingBuilder 提供了一对方法 withConverter,它们都采用一对 SerializableFunction 对象。

➥ 那么如何定义一对SerializableFunction objects/classes呢?

我注意到这个接口列出了一个已知的子接口 ValueProvider<SOURCE,TARGET>。这看起来很眼熟,我有预感它是轻松定义简短转换器的关键。但是我不太理解 lambda 的语法以及这里发生的一切。

不是 问如何编写 class 实现 Converter。我在问如何编写一对 SerializableFunction 参数以作为项目符号项传递给上面列出的 Binder.BindingBuilder::withConverter 方法。

引用 that JavaDoc:

Interface Binder.BindingBuilder<BEAN,TARGET>

withConverter

default <NEWTARGET> Binder.BindingBuilder<BEAN,NEWTARGET> withConverter(SerializableFunction<TARGET,NEWTARGET> toModel, SerializableFunction<NEWTARGET,TARGET> toPresentation)

Maps the binding to another data type using the mapping functions and a possible exception as the error message.

The mapping functions are used to convert between a presentation type, which must match the current target data type of the binding, and a model type, which can be any data type and becomes the new target type of the binding. When invoking bind(ValueProvider, Setter), the target type of the binding must match the getter/setter types.

For instance, a TextField can be bound to an integer-typed property using appropriate functions such as: withConverter(Integer::valueOf, String::valueOf);

Type Parameters:

NEWTARGET - the type to convert to

Parameters:

toModel - the function which can convert from the old target type to the new target type

toPresentation - the function which can convert from the new target type to the old target type

Returns:

a new binding with the appropriate type

Throws:

IllegalStateException - if bind has already been called

您可以通过将两个 lambda 表达式传递给 withConverter 来做到这一点,就像这样:

binder.forField(textField)
.withConverter(text -> UUID.fromString(text), uuid -> uuid.toString())
.bind(/* ... */);

如果你需要更复杂的转换,那么lambda的右边可以用括号括起来,例如

binder.forField(textField).withConverter( text -> {
    if ( text == null ) {
       return something;
    } else {
       return somethingElse;
    } 
}, uuid -> { return uuid.toString(); } )
.bind(/* ... */);

如果您多次需要您的转换器,我建议创建一个单独的 class 实现接口 com.vaadin.data.Converter。但是,正如您已经知道的那样,也可以使用 lambda(请参阅@ollitietavainen 的回答)。但这不是 Vaadin 特有的,它是一个 Java 8+ 特性,您可以阅读 e.g. here。基本上,只要对象只用一种方法实现接口,您就可以使用 lambdas。