通过定义一对 SerializableFunction 对象为数据绑定提供转换器
Provide a Converter for data-binding by defining a pair of SerializableFunction objects
在 Vaadin 8 Framework 和 Vaadin 10 Flow 中,数据绑定功能允许我们提供一个 Converter
来调解小部件的预期数据类型(例如 String
为 TextField
) 和 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
对象。
Binder.BindingBuilder::
withConverter
(SerializableFunction<TARGET,NEWTARGET> toModel, SerializableFunction<NEWTARGET,TARGET> toPresentation)
Binder.BindingBuilder::
withConverter
(SerializableFunction<TARGET,NEWTARGET> toModel, SerializableFunction<NEWTARGET,TARGET> toPresentation, String errorMessage)
➥ 那么如何定义一对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。
在 Vaadin 8 Framework 和 Vaadin 10 Flow 中,数据绑定功能允许我们提供一个 Converter
来调解小部件的预期数据类型(例如 String
为 TextField
) 和 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
对象。
Binder.BindingBuilder::
withConverter
(SerializableFunction<TARGET,NEWTARGET> toModel, SerializableFunction<NEWTARGET,TARGET> toPresentation)
Binder.BindingBuilder::
withConverter
(SerializableFunction<TARGET,NEWTARGET> toModel, SerializableFunction<NEWTARGET,TARGET> toPresentation, String errorMessage)
➥ 那么如何定义一对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 toParameters:
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 typeReturns:
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。