Skip to content

How to use ObjectField?

Miki edited this page Sep 10, 2022 · 1 revision

Overview

In short, ObjectField is a (Vaadin) field of type T that displays (Vaadin) fields for each Property of that object. This happens in order:

  • properties of the object are obtained with a PropertyProvider; if there are no changes in properties, existing (Vaadin) fields are reused - nothing else happens;
  • those properties are then grouped with a PropertyGroupingProvider, such that each group has a name;
  • for each group a layout is built using a PropertyGroupLayoutProvider;
  • each property in each group is mapped to a (Vaadin) field using PropertyComponentBuilder;
  • eachj field is then added to its group's layout (if the group does not have any layout, then the component is added to the ObjectField's main layout);
  • each component is configured with ComponentConfigurators
  • each component group is configured with ComponentGroupConfigurators
  • all components are configured as a single group (using the above ComponentGroupConfigurators, but with null as the group name).

After all of the above is done, ObjectField obtains a value for each Property and then sets value of the corresponding (Vaadin) field.

The above mechanism allows modifying the ObjectField in almost every way, except the order in which things happen. However, it comes at a significant price of steep learning curve.

Reasonable defaults

Out-of-the-box ObjectField is capable of displaying any object by:

  • using reflection to inspect (Java) fields, their getters and setters (considering is/are prefixes for boolean and Boolean)
  • using single-Property groups and no separate layouts (all components end up in the main layout)
  • using LabelField (with toString) as the default component for everything
  • using no configurators

ObjectFieldFactory

To reuse common settings across different ObjectFields (regardless of their type), use ObjectFieldFactory. By itself it is configured to:

  • use reflection to inspect (Java) fields, setters and getters and to collect various metadata based on annotations
  • use metadata to group related properties (otherwise using one property per group)
  • build components using best educated guess
  • configure labels and read-only-ness based on metadata (default label being human-readable name of the Property)
  • assign each group and each component class names for easy styling

Annotations

The following annotations can be used:

  • FieldOrder defines the order in which (Vaadin) fields are displayed
  • FieldGroup specifies groups
  • FieldCaption overrides the default caption
  • BigField on a String property will result in a text area being shown, rather than a text field
  • ComponentId and ComponentStyle allow setting id of and adding styles to the constructed (Vaadin) field, respectively
  • ShowFieldAs overrides the default (Vaadin) field with the provided one that must have a public, no-arg constructor
  • BuildFieldWith has the same effect as ShowFieldAs, but allows more control over the (Vaadin) field by using a builder (that must have a public, no-arg constructor)

The above annotations can be used on a (Java) field, a setter or a getter associated with the (Java) field. Associated means the name of the method follows Java naming pattern (SomeType field -> setField(SomeType value) and SomeType getField(), with isField and areField also supported for boolean and Boolean types).

Note that technically the annotations are converted to metadata, and it is the presence of the metadata that defines what component is created, how it is configured, etc. So it is entirely possible to build a PropertyProvider that obtains the same metadata through different means and still enjoy the benefits of ObjectFieldFactory.

Default components

Again, there are some reasonable defaults:

  • boolean properties are mapped to Checkbox
  • various number types are mapped to supported Super___Field (integer, long, double and BigDecimal)
  • String is shown as SuperTextField or SuperTextArea
  • LocalDate and LocalDateTime with its corresponding Super___Picker
  • List<X> and Set<X> are shown with a CollectionField that uses ObjectField<X> for unknown types, and above types for everything else
  • Map<K, V> is shown with a MapField with ObjectField<X> for unknown types, and above types for everything else

Note that in the above if creating an ObjectField fails, it should be replaced with a LabelField.

Configuration options

As with ObjectField, the factory is highly configurable through its public methods:

  • layouts for collection, object and map fields
  • style names for group layouts and components in groups inside ObjectFields
  • instance suppliers for objects and empty collections

In addition to the above, a number of protected methods (like buildAndConfigurePropertyProvider) can be overwritten in a subclass of ObjectFieldFactory.

Limitations of ObjectFieldFactory

There are some limitations:

  • objects are scanned via reflection
  • creating objects by default is done by reflection, but can be overwritten by adding instance suppliers
  • only List, Set and Map are supported; custom collection types can be added, but they must have its first generic attribute as the type that is contained in the collection
  • default layouts are all FlexLayoyuts (columns for main layouts, rows for nested ones)