New & Noteworthy

1.0-SNAPSHOT

Encapsulation of Vaadin dependencies into linkki-core-vaadin7

All Vaadin dependencies have been moved from linkki-core to linkki-core-vaadin7. Any uses of UI framework (for example Vaadin) API from the core is now handled via the UiFramework class. It is recommended that you also use it instead of directly calling Vaadin API where applicable.

Table 1. Methods of the UiFramework
New method Vaadin method Notes

UiFramework.getLocale()

UiUtils.getUiLocale()/UI.getCurrent().getLocale()

the locale defined for the UI session, may differ from the System locale

If your application depends on linkki-application-framework you don’t have to change anything, as it now references the new linkki-core-vaadin7. If your application uses linkki-core directly, you need to update your Maven dependency from linkki-core to linkki-core-vaadin7: This is the necessary maven dependency:
<dependency>
	<groupId>org.linkki-framework</groupId>
	<artifactId>linkki-core-vaadin7</artifactId>
</dependency>
Introduction of linkki Severity for Message and MessageList

To make the linkki Message and MessageList independent of Vaadin, a new enum Severity is introduced to avoid using the Vaadin ErrorLevel directly. Consequently, several methods of Message and MessageList are changed:

Table 2. API changes in org.linkki.core.message
Until now

A Vaadin independent enum indicating the kind of severity a message can have.

New

Notes

ErrorLevel

Severity

February 5th, 2019

cancelHandler in OkCancelDialog

We added a cancelHandler to OkCancelDialog which will be called when the cancel button is invoked. To create a new OkCancelDialog with a cancelHandler, the new extended constructor can be used. Alternatively, PmoBasedDialogFactory has also been extended by a new newOkCancelDialog method that accepts a cancelHandler in addition to the okHandler.

As the new functionality further increases the number of arguments that can be passed to OkCancelDialog, a Builder is introduced to simplify the creation of a dialog. OkCancelDialog provides a new static method builder(String) that creates a new builder:

OkCancelDialog.builder(caption)
              .cancelHandler(cancelHandler)
              .build();

The builder also supports multiple content components to be consistent to the newOkCancelDialog method in PmoBasedDialogFactory. As the OkCancelDialog should now be created using the builder, the existing constructors using a nullable content component are deprecated. A new constructor taking all configurations is provided for overriding.

New creation mechanism of aspects

The creation of linkki aspects has changed. Instead of giving the LinkkiAspectDefinition implementation class as value for the @LinkkiAspect annotation, an AspectDefinitionCreator implementation has to be used now.

This offers the benefit that the LinkkiAspectDefinitions do no longer need to depend on the corresponding annotations. The values from the annotations can be passed by the AspectDefinitionCreator. This makes the aspect definitions better testable and allows the use of the same aspect definition with multiple different annotations. The initialize() method of the LinkkiAspectDefinition, that up to now was called after creation via default constructor, was removed. The values previously read from the annotation in that method should now be read in the AspectDefinitionCreator and passed to the LinkkiAspectDefinition 's constructor, thus allowing instantiating aspect definitions from sources other than annotations.

API Changes

This feature brings several changes in the API:

  • Existing LinkkiAspectDefinitions can no longer be used in @LinkkiAspect directly. It requires an implementation of AspectDefinitionCreator to create the aspect definitions.

    Reading of the value in the AspectDefinitionCreator
        class BindTooltipAspectDefintionCreator implements AspectDefinitionCreator<@NonNull BindTooltip> {
    
            @Override
            public LinkkiAspectDefinition create(BindTooltip annotation) {
                return new BindTooltipAspectDefinition(annotation.tooltipType(), annotation.value());
            }
    
        }
  • initialize(Annotation) is removed from the LinkkiAspectDefinition interface. All necessary information should be directly passed to the constructor instead.
    Previously, the initialize method had the responsibility of reading the relevant attributes from the given annotation. To make the aspect definition more flexible, we recommend moving this responsibility to the creator. The constructor of the aspect definition then directly take the relevant values.

    Previous instantiation of the aspect definition with annotation
        @SuppressWarnings("null")
        private TooltipType type;
    
        @Override
        public void initialize(Annotation annotation) {
            this.type = ((BindTooltip)annotation).type();
        }
    New instantiation of the aspect definition with value
      private final TooltipType type;
    
      public LabelAspectDefinition(TooltipType type) {
            this.type = type;
      }
  • If the existing LinkkiAspectDefinition extends CompositeAspectDefinition, the definition itself may not be needed any more. Instead, it can be turned into a aspect definition creator that creates a CompositeAspectDefinition in the create(Annotation) method.

    Creation of a CompositeAspectDefinition
    public class MyAspectDefinitionCreator implements AspectDefinitionCreator<@NonNull MyAnnotation> {
    
        @Override
        public LinkkiAspectDefinition create(MyAnnotation annotation) {
            return new CompositeAspectDefinition(
                    new LabelAspectDefinition(annotation.label()),
                    new VisibleAspectDefinition(annotation.visible()),
                    new FieldValueAspectDefinition(),
                    new ReadOnlyAspectDefinition());
        }
    }
  • FieldAspectDefinition has been a composite aspect definition for annotations that are annotated with @LinkkiBindingDefinition. This class is now removed as it is directly created as a composite aspect definition in FieldAspectDefinitionCreator. If you want to reuse this aspect definition, you can use the creator directly with @LinkkiAspect(FieldAspectDefinitionCreator.class) on you annotation class. Other aspects that are specific to you annotation can then be added in a separate @LinkkiAspect annotation.

Binding of aspects in ContainerPmo

The items, page length, and footer of a table are now bound to the ContainerPmo 's existing methods getItems(), getPageLength(), and getFooterPmo() using aspects. Consequently, getFooterPmo() is now bound fully dynamically. This fixes a previous bug that the footer is not removed dynamically once created.

Binding of labels as an aspect

The label is now bound using the aspect LabelAspectDefinition. If you have created a custom annotation that does not use the common FieldAspectDefinition you might need to add the new LabelAspectDefinition to your annotation.

label now mandatory in UI annotations

Our experience in multiple projects has shown that the label is specified directly with the field annotation in almost all cases. Even if the label is translated in linkki-messages.properties, it is useful to declare the label in the field annotation for documentation purposes. Therefore, the label property is now mandatory in all UI annotations except @UIButton and @UICheckBox.

Until now, there is a rarely known fallback value for the label attribute which is the capitalized property name. Thus, there was a special property noLabel to disable the label.

With this version the fallback to the property name was removed. Therefore the noLabel property was removed, too. To show no label, simply use an empty String.

In @UIButton and @UICheckBox there was a property showLabel instead of noLabel because showing no label is the default for buttons and check boxes. Instead, both fields have a caption which is shown on top of the button or to the right of the check box. The property showLabel was removed, the default for label is still the empty String.

Default methods from interfaces in PMO classes

linkki now finds annotated methods that are inherited from interface default methods.

Custom @Bind-like annotation using Binder and fallback for pmoProperty in @Bind

The Annotation @Bind was refactored to allow creating other variations (see Custom Binding Annotation).

During this refactoring, a fallback mechanism to determine the pmoProperty attribute from the name of the annotated method (or field) has been implemented as well.

Deprecated classes

  • The methods sizedLabel(AbstractOrderedLayout, String) and sizedLabel(Layout, String, ContentMode) in the ComponentFactory have been marked as deprecated, as they duplicate the newLabelWidthUndefined methods with the same parameters which better fit the naming of the other methods in the class.

  • The classes PmoBasedTableSectionFactory and SectionCreationContext have been deprecated in favor of a unified class PmoBasedSectionFactory. You could use PmoBasedSectionFactory.createSection(Object, BindingContext) method to create all kinds of sections annotated with @UISection. If the PMO class implements ContainerPmo it automatically creates a TableSection.

  • The method BindingContext.createDispatcherChain(Object, BindingDescriptor) was deprecated. If you had overwritten this method, pass your PropertyDispatcherFactory to the new constructor BindingContext(String, PropertyBehaviorProvider, Handler, PropertyDispatcherFactory).

  • The signatures of the methods in PropertyDispatcherFactory have changed. Instead of the BindingDescriptor it directly takes the newly introduced BoundProperty which holds the reference to the bound PMO property name as well as the model object name and model object property name.

November 29th, 2018

ApplicationHeader#addRightComponents() deprecated

The addRightComponents() method in ApplicationHeader is deprecated as components added in this method were not automatically aligned to right. Use addRightComponents(HorizontalLayout) instead of which the method argument is a right aligned layout.

The CSS style LinkkiStyles#APLICATION_HEADER and LinkkiStyles#APPLICATION_HEADER_RIGHT have been modified as the previously included style are not needed anymore.

@ModelObject can be applied to instance variables

The annotation @ModelObject can now be added to an instance variable. It is not necessary to create a getter for the model object any more. For more information refer to the documentation.

November 22th, 2018

From now on linkki uses eclipse null annotations from the org.eclipse.jdt package. To use it, you have to add this dependency to your pom:

<dependency>
  <groupId>org.eclipse.jdt</groupId>
  <artifactId>org.eclipse.jdt.annotation</artifactId>
  <version>2.2.0</version>
  <scope>provided</scope>
</dependency>

Also you have to make sure that the right annotations are used in your project configuration:

  1. Enabled annotation-based null analysis in the project configuration

  2. Configure the default annotations for null specifications with the following annotations as primary annotation:

    • 'Nullable' annotations: org.eclipse.jdt.annotation.Nullable

    • 'NonNull' annotations: org.eclipse.jdt.annotation.NonNull

    • 'NonNullByDefault' annotations: org.eclipse.jdt.annotation.NonNullByDefault

7Nov18 PropertiesNullHandling
Figure 1. 1 Project configuration page for null analysis
7Nov18 PropertiesNullHandling Configure
Figure 2. 2 Configuration for "Annotations for Null Specifications"

For more information about the null analysis in eclipse refer to the eclipse JDT documentation.

There is a bug in Eclipse where you get compile errors in your projects if your project configuration is not correct, for example if you write javax.annotation.NonNull instead of javax.annotation.Nonnull (Eclipse bug). Check for correct spelling in the configuration if you get the warning "The type …​ cannot be resolved. It is indirectly referenced from required .class files".

November 7th, 2018

Moved the class BindReadOnly from package org.linkki.core.binding.aspect to org.linkki.core.ui.section.annotations.

October 10th, 2018

modelObject and modelAttribute are added to @Bind as parameters. These attributes can be used together with the annotation @ModelObject to bind the annotated PMO property directly to a model attribute. In addition, the quality of error messages is improved.

October 4th,2018

The annotation @UIToolTip has been deprecated and reintroduced as @BindTooltip.

The changes in Detail:

  • @BindTooltip uses "tooltip" as a property (previously "toolTip")

  • @BindTooltip uses BindTooltipType as a type (previously ToolTipType)

  • @BindTooltip with a dynamic tooltip requires the corresponding method to be named getXYZTooltip() (lower case "t" here as well, instead of getXYZToolTip())

Migrating existing code to @BindTooltip is recommended.

September 10th, 2018

BindReadOnly

A new annotation @BindReadOnly is introduced to provide read-only behavior to components.

The @BindReadOnly annotation must be placed after @Bind or @UI-annotations as the read-only state might have already be affected by these annotations.
This annotation should be used only in exceptional cases, since most of the behavior is better controlled by PropertyBehavior.

August 29th, 2018

Unified Header Height

The height of section headers with and without buttons is now set to the same.

August 27th, 2018

Default PropertyBehaviors

Often, a property behavior only needs to control one of the states (writable, visible, shows messages). Thus, the interface PropertyBehavior (see PropertyBehaviors) now offers static methods to create instances that override just one of its methods, for example PropertyBehavior#visible.

There are two methods for each of the states that can be controlled by a behavior: * One static method creates the behavior by taking a BiPredicate<Object, String> that is called for every bound object and property. * The other one takes a BooleanProvider that decides the state regardless of the property and bound object.

As a read-only state is often used as the negation of the writable state, additional static methods are offered for easy creation of read-only property behaviors.

The PropertyBehaviorProvider interface also received a static method to create an instance from a variable argument array of PropertyBehaviors.

August 16th, 2018

ApplicationFooter now hidden by default

As the application information displayed in the ApplicationFooter is included in the newly introduced ApplicationInfoDialog, the footer is now hidden by default.

August 1st, 2018

Hierarchical Tables

The tables created for a ContainerPmo can now contain hierarchical data that is displayed in a TreeTable. See HierarchicalRowPmo for details.

API Changes

While implementing the hierarchical tables, we refactored the BindingContext and TableBinding. The TableBinding is now itself a BindingContext. The BindingContext does no longer distinguish between ElementBindings and TableBindings so the relevant methods add(elementBinding)/add(TableBinding) and getElementBindings()/getTableBindings() have been united to add(Binding) and getBindings(). Some methods on BindingContext have been deprecated and reintroduced with new names and improved documentation:

Old New Notes

updateMessages

displayMessages

now returns a filtered MessageList like Binding#displayMessages

updateUI

modelChanged

should be called when the context’s after update handler should also be notified

AbstractPage now calls uiUpdated() in reloadBindings() instead of modelChanged(). As stated in JavaDoc, reloadBindings() should only refresh the UI, which is not a model update. Thus, modelChanged() is not the correct method to call. In practice, reloadBindings() is mainly used to react to tab changes in TabSheetAreas which should not trigger UiUpdateObservers. This correction of behavior may result in components not being initially updated if it is registered as a UiUpdateObserver and relies on being notified initially.

The LinkkiInMemoryContainer now implements Container.Hierarchical to support hierarchical data, and it no longer wraps its items in a LinkkiItemWrapper. It’s methods removeAllItems and addAllItems that previously were always used in unison have been deprecated and replaced by a single setItems-Method.

Collapsible Table Columns

Table columns can now be set as collapsible and collapsed, using the new corresponding properties in the UITableColumn annotation.

July 18th, 2018

Help menu in ApplicationHeader

The right MenuBar of the ApplicationHeader is now equipped with a help menu which provides an ApplicationInfoDialog by default. It is customizable implementing ApplicationConfig and extending ApplicationHeader and ApplicationInfoPmo.

The ApplicationFooter is now defined in ApplicationConfig as optional. In order to hide it, override ApplicationConfig#getFooterDefinition() with Optional.empty().

June 27th, 2018

Headline

Headline now extends HorizontalLayout instead of CustomComponent. Hence Headline#getHeaderLayout() isn’t needed anymore and was dropped. The method #getPolicyInfoLabel() was dropped too. If you have overridden this method to modify the shown title, use the new constructor Headline(label) instead. The Headline’s label is now annotated with @Bind, binding the field to a pmo property which’s name is accessible at Headline#HEADER_TITLE. Finally, the method setHeadline(String) is deprecated, use setTitle(String) instead.

June 14th, 2018

SidebarSheet

The SidebarSheet was slightly refactored. It now offers lazy initialization, which means its content is not created until the sheet is selected for the first time. Additionally it is possible to add an UiUpdateObserver that is triggered every time the sheet is selected.

The old constructor is deprecated and will be replaced. The new constructors offers a more consistent API.

There is a new documentation chapter explaining the sidebar layout.

June 12th, 2018

linkki is getting independent from cdi

All dependencies to and usages of CDI have been removed from linkki to better allow linkki's usage in different environments. This refactoring makes some necessary changes:

  • LinkkiUi was introduced to have an easy setup for a new linkki application. Implement your own subclass to specify your configuration.

  • ApplicationFrame is separated to ApplicationLayout and ApplicationNavigator. The first only contains the UI layout of the application, the second is a subclass of vaadin’s Navigator and enhances it with some convenience methods. Both are instantiated using the ApplicationConfig and are no longer injected. There are some additional methods to specify the ApplicationHeader or `ApplicationMenuItemDefinition`s separately.

  • To specify the ApplicationConfig, implement a subclass of LinkkiUI and provide your configuration via constructor or by calling configure(ApplicationConfig).

  • The interface AutoDiscoveredConverter has been removed; Converters must now be manually registered using ApplicationConfig#getConverterFactory. The default contains all Java 8 date type converters.

    • The LinkkiConverterFactory now accepts a sequence supplier as its constructor and offers a default sequence containing the Java 8 date converters

    • The Joda date converters can be now found in the JodaConverters#DEFAULT_JODA_DATE_CONVERTERS

  • The package org.linkki.util.cdi and its children have been removed

  • The LoginServlet was removed from linkki; associated style classes have also been removed. For Faktor Zehn users, an equivalent class has been created in f10-commons-auth-spring, others are free to implement their own login solution.

  • DefaultPmoBasedSectionFactory is deprecated and will be removed in the next version. Simply use PmoBasedSectionFactory instead.

You can see an example in our SampleApplicationUI

@Theme(value = "sample")
@PreserveOnRefresh
public class SampleApplicationUI extends LinkkiUi {

    private static final long serialVersionUID = 1L;

    public SampleApplicationUI() {
        super(new SampleApplicationConfig());
    }

    @Override
    protected void init(VaadinRequest request) {
        super.init(request);
        addView(MainView.NAME, MainView.class);
    }

}

April 10th, 2018

NLS Service

linkki now always use DefaultPmoNlsService as PmoNlsService and DefaultNlsService as NlsService. That means custom implementations of these interfaces are not automatically used by linkki anymore. If an individual implementation of these classes were/have to be used, please contact the linkki development team.

BeanInstantiator

org.linkki.util.cdi.BeanInstantiator is deprecated and will be removed the next release. Instead, use org.apache.deltaspike.core.api.provider.BeanProvider. Test cases which need the CDI environment provided by BeanInstantiator can extend TestWithBeanProvider from f10-commons-cdi-test:

<dependency>
    <groupId>de.faktorzehn.commons</groupId>
    <artifactId>f10-commons-cdi-test</artifactId>
    <version>18.7.0</version>
</dependency>

March 22th, 2018

No More Binding Private Methods

Previously, linkki allowed some annotations to be used on non-public methods when using Binder to manually create bindings. This is no longer possible, as we believe that all methods used by linkki’s binding should be public and not be accessed by reflection hacks.

February 15th, 2018

Binding Aspects

The binding mechanism was redesigned fundamentally. Everything that could be bound to a component such as the value, the enabled state, the visible state, available values etc. are now configured by so called binding aspects. This new mechanism makes it easier to include other UI component properties into the dynamic binding mechanism. It also greatly simplify the process of implementing custom binding aspects.

Due to the refactoring we could simplify and consolidate several classes. If you have created your own binding annotations or a customized property dispatcher chain there may be some need of adaption:

  1. The interface UIElementDefinition is merged into BindingDefinition. Its implementations such as UIFieldDefinition are removed. If you have implemented your own field annotation that implements UIElementDefinition or UIFieldDefinition, just implement BindingDefinition directly instead. In addition to your @LinkkiBindingDefinition annotation you have to specify the bound aspects using @LinkkiAspect annotation. You could use the composite aspect FieldAspectDefinition which defines the most common aspects for AbstractFields. The aspect for available values is no longer retrieved via BindingDefinition. If you want to include this aspect just create a subclass of AvailableValuesAspectDefinition that suits your annotation and add it to your custom annotation using @LinkkiAspect.

  2. The AnnotationDispatcher is renamed to StaticValueDispatcher

  3. The implementations of BindingDescriptor are merged into ElementDescriptor for all field bindings. BindAnnotationDescriptor is used for the special case of @Bind annotation.

  4. The subclasses of ElementBinding for components are united to ComponentBinding.

We decided to not keep the deprecated implementations because the refactoring changes will have little effect on client code and keeping deprecated classes would significantly increase maintenance effort.

January 15th, 2018

open() in OkCancelDialog

With the new method open() in OkCancelDialog, a dialog can be directly opened by calling dialog.open() instead of using PmoBasedDialogFactory.open(dialog). The open() method can be extended to add additional behaviors to the dialog. By default, a UriFragmentChangedListener is added upon opening, ensuring that the dialog is properly closed on URL change. If this behavior should be adapted, make sure that all existing dialogs are opened using the new open() method.

The open(OkCancelDialog) method in PmoBasedDialogFactory is deprecated and will be removed in the future.

Januar 14th, 2018

Changed package for PropertyBehavior

The class PropertyBehavior was moved from org.linkki.core.binding.aspect to org.linkki.core.binding.behavior.

January 10th, 2018

New component Headline

A new standard component for the application framework called org.linkki.framework.ui.component.Headline was introduced. It is used to show a headline at the top of a page below the application header. For customizing it is intended to subclass Headline and add further components.

For styling the Headline there is a new stylesheet class called linkki-headline.

OkHandler now deprecated

The interface OkHandler is no longer used by linkki and will be removed in version 1.0. The already existing interface Handler has the same functionality and should be used instead.

Annotation @UISection optional

The annotation @UISection is now optional. If a class without that annotation is used as a PMO, the annotation’s default values (column layout with one column, no caption, not closable, id equal to the class' simple name) are used for the resulting section.

December 12th, 2017

Captions for Checkboxes

linkki versions up to 0.9.20171123 treated checkboxes like any other input field concerning labels: The label is displayed on the left, preceding the input field. But in most UI layouts, checkboxes are followed by a caption instead. To facilitate this layout, the @UICheckBox now has a caption property that must be set. The old label can still be used, but the default value for noLabel has been switched to true, so that nolabel=false has to be used where a label should be displayed.

If a @UICheckBox is used in a table column and nolabel=false is set, the label is displayed as the column header, while the caption remains at the right of the individual checkboxes in the table cells.