Skip to content

Instantly share code, notes, and snippets.

Last active April 25, 2017 12:23
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Vaadin CustomField for a Value-type, that wrapps a field for a Presentation-type and uses a Converter to transform between the two
package net.ofnir.vaadin.form
import com.vaadin.shared.Registration
import com.vaadin.ui.AbstractField
import com.vaadin.ui.Component
import com.vaadin.ui.CustomField
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
* Adapts a Field to another type via a Converter.
* @param < VALUE > Type this field can handle
* @param < PRESENTATION > Type of the wrapped field
class ConverterField<VALUE, PRESENTATION> extends CustomField<VALUE> {
private final AbstractField<PRESENTATION> wrappedField
private final Converter<PRESENTATION, VALUE> converter
private final Binder<ValueContainer<VALUE>> binder
private VALUE oldValue
* @param wrappedField The field to edit the converted value.
* @param converter Converter to transform between the edited type and the type of the wrapped field.
* @param nullRepresentation Optional `null` applied before the converter
ConverterField(AbstractField<PRESENTATION> wrappedField, Converter<PRESENTATION, VALUE> converter, Optional<PRESENTATION> nullRepresentation = Optional.empty()) {
this.wrappedField = wrappedField
caption = wrappedField.caption
this.converter = converter
binder = new BeanValidationBinder<ValueContainer<VALUE>>(ValueContainer)
def builder = binder.forField(wrappedField)
builder = builder.withNullRepresentation(it) // before converter!
// @Override
protected Component initContent() {
return wrappedField
// @Override
protected void doSetValue(VALUE value) {
oldValue = value
binder.bean = new ValueContainer<VALUE>(value)
VALUE getValue() {
return binder.bean.value
Registration addValueChangeListener(HasValue.ValueChangeListener<VALUE> listener) {
return binder.addValueChangeListener({ HasValue.ValueChangeEvent<PRESENTATION> event ->
assert event.source == wrappedField, "A binder will only ever fire change events for the bound fields"
listener.valueChange(new HasValue.ValueChangeEvent<VALUE>(this, oldValue, event.userOriginated))
oldValue = getValue()
} as HasValue.ValueChangeListener<VALUE>)
@EqualsAndHashCode(includes = ['value'])
static class ValueContainer<VALUE> {
VALUE value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment