Class FieldBuilderCustomField<T>

Type Parameters:
T - field value type
All Implemented Interfaces:
AttachNotifier, BlurNotifier<CustomField<T>>, DetachNotifier, Focusable<CustomField<T>>, FocusNotifier<CustomField<T>>, HasElement, HasEnabled, HasHelper, HasLabel, HasSize, HasStyle, HasTheme, HasValidation, HasValue<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, HasValueAndElement<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, HasTooltip, HasValidationProperties, InputField<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, Serializable, ValidatingField<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>

public class FieldBuilderCustomField<T> extends BinderCustomField<T>
Support superclass that mostly automates the creation of CustomFields for editing any model type using sub-fields automatically generated from FieldBuilder annotations to arbitrary recursion depth.

This class is just a BinderCustomField that uses a FieldBuilder to generate the sub-fields.

Example

Suppose model class Contract has a "term" property of type DateInterval which has a start and end date. We want to use FieldBuilder annotations to define the editor fields for the properties of Contract, including "term", but for that to work we will need to specify a custom field to handle the "term" property. We also want this custom field to contain the logic for laying out the two date picker components as well as for validating proper ordering.

For example:


 // This is complex type that we wish to edit with a single CustomField
 public class DateInterval {

     @FieldBuilder.DatePicker(label = "Start date")
     public LocalDate getStartDate() { ... }
     public void setStartDate(LocalDate date) { ... }

     @FieldBuilder.DatePicker(label = "End date")
     public LocalDate getEndDate() { ... }
     public void setEndDate(LocalDate date) { ... }
 }

 // This is the corresponding custom field
 public class DateIntervalField extends FieldBuilderCustomField<DateInterval> {

     public DateIntervalField() {
         super(DateInterval.class);
     }

     // Customize how we want to layout the subfields
     @Override
     protected void layoutComponents() {
        this.add(new HorizontalLayout(
          new Text("From"), this.getField("startDate")), new Text("to"), this.getField("endDate"));
     }

     // Bean level validation: ensure end date is after start date
     @Override
     public ValidationResult validate(DateInterval dates, ValueContext ctx) {
         if (dates.getStartDate().isAfter(dates.getEndDate())
             return ValidationResult.error("Dates out-of-order"));
         return super.validate(dates, ctx);           // always ensure superclass contraints apply also
     }
 }
 

Once that's done, using FieldBuilder works recursively and automatically for this multi-level class:


 public class Contract {

     @FieldBuilder.CheckBox(label = "Approved?")
     public boolean isApproved() { ... }
     public void setApproved(boolean approved) { ... }

     @FieldBuilder.CustomField(label = "Term", implementation = DateIntervalField.class)
     public DateInterval getTerm() { ... }
     public void setTerm(DateInterval term) { ... }
 }
 
See Also: