New & Noteworthy

1.0-SNAPSHOT

With this version, linkki now supports both Vaadin Framework 7 and Vaadin Framework 8. If you intend to use linkki with Vaadin Framework 8, we highly recommend migrating to the previous linkki version first as Vaadin Framework 8 includes several major changes that also leads to changes in the linkki API. Also, it is best to first free your project from deprecated warnings related to linkki. Although we tried our best to keep the API stable, some concepts had to be reworked fundamentally, making it impossible to carry the existing API over to the new version.

linkki for Vaadin Framework 8

Up to now, linkki could only be used with Vaadin Framework 7. Now, you can decide if you want to use linkki with Vaadin Framework 7 or Vaadin Framework 8. As Vaadin Framework 7 will not be maintained anymore in 2020, the development of linkki will be primarily focused on Vaadin 8 from now onwards.

Vaadin Framework 8 poses a large release containing major improvements and changes. If you want to use linkki with Vaadin Framework 8 but prefer a more granular migration process, you can first switch to linkki for Vaadin 7, then move forward to linkki for Vaadin 8 after having adjusted to the changes.

Migrating to linkki for Vaadin 7

If you want to continue using linkki with Vaadin 7, the only Vaadin 7 specific step is to replace the linkki dependencies with the new linkki Vaadin 7 dependencies for linkki-core or linkki-application-framework:

<!-- Replacement for the existing linkki-core dependency -->
<dependency>
  <groupId>org.linkki-framework</groupId>
  <artifactId>linkki-core-vaadin7</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

<!-- Replacement for the exsiting linkki-application-framework dependency -->
<dependency>
  <groupId>org.linkki-framework</groupId>
  <artifactId>linkki-application-framework-vaadin7</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

Now you can continue with the general changes that apply to both Vaadin 7 and Vaadin 8 migration. These are listed below the Vaadin specific migration steps.

Migrating to linkki for Vaadin 8

Migration Script

To minimize the migration effort, we created shell scripts to help with the changes that can be easily automated.

The find and replaces are defined in The file migrate.sed and search_replace.sh executes these commands. The easiest way to use the migration script is to put both files in your project directory and run "./search_replace.sh ." in your terminal. The scripts can be executed in any terminal that supports shell scripts, including the git bash.

Maven Dependency

The very first step for the migration is to include the new linkki Vaadin 8 dependencies for linkki-core or linkki-application-framework:

<!-- Replacement for the existing linkki-core dependency -->
<dependency>
  <groupId>org.linkki-framework</groupId>
  <artifactId>linkki-core-vaadin8</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

<!-- Replacement for the exsiting linkki-application-framework dependency -->
<dependency>
  <groupId>org.linkki-framework</groupId>
  <artifactId>linkki-application-framework-vaadin8</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
LinkkiConverterFactory

The configuration of custom converters has changed. Instead of the existing ConverterFactory, a LinkkiConverterRegistry is now used in ApplicationConfig.

Table 1. Cooperating custom converters
Until Now New
public class MyApplicationConfig implements ApplicationConfig {
  ...

  @Override
  public ConverterFactory getConverterFactory() {
      return new LinkkiConverterFactory(this::getConverters);
  }

  private Sequence<Converter<?, ?>> getConverters() {
      return LinkkiConverterFactory.DEFAULT_JAVA_8_DATE_CONVERTERS
              .with(new MyConverter());
  }
}
public class MyApplicationConfig implements ApplicationConfig {
  ...

  @Override
  public ConverterRegistry getConverterRegistry() {
      return LinkkiConverterRegistry.DEFAULT
              .with(new MyConverter());
  }
}

This change is relevant for you if you have overriden ApplicationConfig#getConverterFactory to use custom converters with linkki default annotations.

Converters are necessary to make linkki UI annotations work for custom data types. By default, linkki UI annotations only work for a very specific data type. @UIDateField for example only works with Java Time LocalDate. If you want to use an annotation with a different data type, you have to provide a converter for the data type. To make the example annotation @UIDateField work with Joda LocalDates, a converter that transforms Joda LocalDates to Java Time LocalDates must be registered to the application.

Prior to this version, we directly utilized the Vaadin ConverterFactory mechanism to register converters. Several default converters were provided in LinkkiConverterFactory that is configured in the ApplicationConfig. There, you can also replace the LinkkiConverterFactory with a custom implementation to include your own converters.

In Vaadin Framework 8, the ConverterFactory mechanism is removed. Without a central registry, converters have to be bound to the input fields directly in Vaadin Framework 8. To mitigate this change for linkki users, linkki now has its own LinkkiConverterRegistry. Custom converters can directly be amended to the default converters by calling LinkkiConverterRegistry.DEFAULT.with(…​).

Joda Time Converters

ConverterFactory was commonly used to incorporate Joda converters that were included in JodaConverters. linkki Vaadin 8 does not support Joda Time any more. If you are still using Joda Time, you now have to create the converters yourself. Vaadin’s LocalDateToDateConverter can serve as a reference when building your own converter.

FieldValueAspectDefinition

FieldValueAspectDefinition is renamed to ValueAspectDefinition which now handles converters and formatters that should be attached to a specific field annotation. Due to this change, it is no longer created by the FieldAspectDefinitionCreator by default.

Custom UI annotation without converter: until now
...
@LinkkiAspect(FieldAspectDefinitionCreator.class)
public @interface UISpecialField { ... }
Custom UI annotation without converter: with linkki Vaadin 8
...
@LinkkiAspect(FieldAspectDefinitionCreator.class)
@LinkkiAspect(ValueAspectDefinitionCreator.class)
public @interface UISpecialField { ... }
Custom UI annotation with custom converter: until now
...
@LinkkiBindingDefinition(SpecialFieldBindingDefinition.class)
@LinkkiAspect(FieldAspectDefinitionCreator.class)
public @interface UISpecialFieldWithConverter { ... }

public class SpecialFieldBindingDefinition implements BindingDefinition {

  @Override
  public Component newComponent() {
       TextField field = new TextField();
       field.setConverter(new MySpecialConverter());
       return field;
   }
  ...
}
Custom UI annotation with custom converter: with linkki Vaadin 8
...
@LinkkiBindingDefinition(SpecialFieldBindingDefinition.class)
@LinkkiAspect(FieldAspectDefinitionCreator.class)
@LinkkiAspect(MyConverterValueAspectDefinitionCreator.class)
public @interface UISpecialFieldWithConverter { ... }

public class SpecialFieldBindingDefinition implements BindingDefinition {

  @Override
  public Component newComponent() {
       return new TextField();
   }
  ...
}

public class MyConverterValueAspectDefinitionCreator implements AspectDefinitionCreator<UiSpecialFieldWithConverter> {

  @Override
   public LinkkiAspectDefinition create(Annotation annotation) {
       return new ValueAspectDefinition(new MySpecialConverter());
   }
}

This change is necessary to comply with the new Vaadin mechanism for converters. Before the migration, converters and formatters that are specific for a UI annotation are added in the newComponent method of the BindingDefinition with setConverter. This is not possible anymore. Thus, the ValueAspectDefinition must take different converters into account depending on the annotation.

For all custom UI annotations that do not use any specific converters, you can simply add the aspect explicitly in a separate @LinkkiAspect annotation using the ValueAspectDefinitionCreator. If your custom UI annotations have previously added a custom converter in the newComponent method of the BindingDefinition, you have to introduce a new Creator that creates a ValueAspectDefinition with the given converter. This also applies to number fields that have previously required a formatter.

ApplicationStyles

The style name ApplicationStyles_SPACING_HORIZONTAL_SECTION is now deprecated and will not be set to a horizontal section anymore. The styles attached to this class name are no longer necessary in linkki for Vaadin 8. As the CSS class is no longer assigned by linkki, you need to adjust the selector in the SCSS file if you have used this class (horizontal-section-spacing) as a selector.

Default spacing in layouts

The default behavior considering spacing and margin has changed in Vaadin layouts. For the migration, make sure to double check all layouts to avoid unwanted spacing.

This change applies to all Vaadin ordered layouts, including HorizontalLayout and VerticalLayout. Spacing adds distance between elements in the layout while margins (which translate to CSS paddings) keep the elements away from the borders. These adjustments keep the elements apart from each other and from the border, making them more accessible and more readable. However, the extra space may not be desired if you are using the layouts as mere wrappers.

Margin and spacing in Vaadin
Figure 1. Margin and spacing in Vaadin

Some linkki layouts are also reworked considering margins. Sections now have a smaller top margin while AbstractPage now has a padding inside of all borders as well as default spacing between the elements. These changes should make the spacing within an AbstractPage more consistent.

Sections that do not have a caption nor any header buttons had a spacer instead of the header. This spacer is removed in the new version as it is often not desired. If you wish to have extra space for a specific section, you can add a top margin in the SCSS theme by selecting the section using the PMO class name or the ID assigned by @SectionId.

Section with no header in linkki Vaadin 7
Figure 2. Section with no header in linkki Vaadin 7
Section with no header in linkki Vaadin 8
Figure 3. Section with no header in linkki Vaadin 8
Width of labels

In Vaadin Framework 8, Label no longer have full width by default. If you have created any Vaadin Label, make sure to check the length of the label to avoid unnecessary changes. Labels that are created with a @Label annotation are not affected.

Now you can continue with the general changes that apply to both Vaadin 7 and Vaadin 8 migration. These are listed below the Vaadin specific migration steps.

Besides the changes in linkki, Vaadin Framework 8 itself comes with several API changes. To migrate your Vaadin native implementations, consult the Vaadin 8 Migration Guide. Note that linkki uses the compatibility layer for Vaadin 7 to be able to use the Vaadin 7 Table component. However, other components from the compatibility layer will not work with linkki-core-vaadin8.

General Changes

Regardless of which Vaadin version you intend to use, there are some general changes that were necessary to separate Vaadin specific implementations.

Encapsulation of Vaadin specific implementations in linkki-core

To make linkki usable with different Vaadin versions, all Vaadin dependencies in linkki-core have been moved to Vaadin specific artifacts. Any uses of UI framework API from the core are now handled via the new UiFramework class. It is recommended that you also use it instead of directly calling Vaadin API where applicable. This especially apply to all UiUtils.getUiLocale() and UI.getCurrent().getLocale() calls.

Table 2. Methods of UiFramework
Until now New Notes

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

UiFramework.getLocale()

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

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, now using the new linkki Severity. Note that the existing methods are directly removed, as it is not possible to deprecate them due to direct Vaadin dependencies.

Table 3. API changes in org.linkki.core.message
Until now New Notes

ErrorLevel

Severity

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

Message

Message(String, String, ErrorLevel)

Message(String, String, Severity)

getErrorLevel

getSeverity

builder(String, ErrorLevel)

builder(String, Severity)

MessageList

getErrorLevel

getSeverity

getFirstMessage(ErrorLevel)

getFirstMessage(Severity)

sortByErrorLevel

sortBySeverity

Removed Generic Type in PmoBasedTableFactory

The generic typ of PmoBasedTableFactory is removed. If you have previously created a new instance of PmoBasedTableFactory using the constructor, you need to remove the generic typ / diamond operator.

ButtonPmo and ButtonPmoBuilder

The interface ButtonPmo describes UI logic for buttons that are e.g. used in the section header. This interface has slightly changed as it used style names and buttons that have to be implemented differently in Vaadin 7 and Vaadin 8.

The existing static methods to create a new button with ButtonPmo are all moved to ButtonPmoBuilder in the linkki-core-vaadin7 or linkki-core-vaadin8 artifact respectively.

Table 4. Creation of buttons with ButtonPmo
Until now New

ButtonPmo#newAddButton(Handler)

ButtonPmoBuilder#newAddButton(Handler)

ButtonPmo#newEditButton(Handler)

ButtonPmoBuilder#newEditButton(Handler)

ButtonPmo#newDeleteButton(Handler)

ButtonPmoBuilder#newDeleteButton(Handler)

In addition to the abstract method onClick, the methods getButtonIcon and getStyleNames have also become abstract.
If you have used this interface as a functional interface, consider using the ButtonPmoBuilder.newEditButton instead. If you implemented the interface in a class and have not implemented getStyleNames yet, you can use ButtonPmoBuilder.DEFAULT_STYLES to recreate the default. As for getButtonIcon, the default used to be set to FontAwesome.PENCIL.

Table 5. Migration of ButtonPmo
Until Now New
ButtonPmo buttonPmo = () -> executeOnClick();
ButtonPmo buttonPmo = ButtonPmoBuilder.newEditButton(() -> executeOnClick());
public class MyButtonPmo implements ButtonPmo {

  @Override
  public void onClick() {...}

  @Override
  public FontAwesome getButtonIcon() {...}
}
public class MyButtonPmo implements ButtonPmo {

  @Override
  public void onClick() {...}

  @Override
  public FontAwesome getButtonIcon() {...}

  @Override
  public List<String> getStyleNames() {
    return ButtonPmoBuilder.DEFAULT_STYLES;
  }
}

Vaadin 8 uses VaadinIcons instead of FontAwesome.

Maven Archetypes for linkki

It is now even easier to set up a new linkki project with the archetypes for vanilla linkki projects and those using CDI or Spring Boot. See Maven Archetypes.

New Features in linkki for Vaadin 8

UI Components for Messages

A utility class MessageUiComponents has been introduced which creates different components to display Message and MessageList. Earlier MessageListPanel was used to show messages, to make the workflow simpler these classes had to be reworked. MessagePmo and MessageRow has been deprecated, instead MessageRowPmo has been created. MessageTablePmo has also been introduced to show messages in table. MessageUiComponents can be used to create MessageTablePmo like.

MessageUiComponents.createMessageTable("Title", () -> (messages), new BindingContext()));
Table 6. List of deprecated classes
Deprecated New classes

MessagePmo

MessageRowPmo

MessageRow

MessageUiComponents#createMessageLabel

MessageListPanel

MessageUiComponents#createMessageTable

CSS style classes are available for linkki-message-table/linkki-message-row and linkki-message-label. In linkki.scss there were some styles (linkki-message-panel, linkki-message-list) defined that had never been set in the MessageListPanel but only in classes from other Faktor Zehn products like Faktor-IPM. Those have been removed from linkki. They are provided below for reference, but a switch to the new message components is recommended.

  .v-panel-content-linkki-message-list {
    max-height: 300px;
  }

  .v-splitpanel-vsplitter-linkki-message-panel-split {
    height: 2px !important;
  }

  .v-panel-linkki-message-panel {
    border: none;
  }

  .v-panel-linkki-message-panel .v-table-cell-content {
    border: none;
    /* for separating lines between the messages:
    border-right: none;
    border-left: none;
    border-color: #ed473b !important;
    */
  }

  .v-panel-linkki-message-panel .v-table-body {
    border: none;
  }

  .v-panel-caption-linkki-message-panel {
    font-size: 110%;
    font-weight: bold;
    background-color: $linkki-color-messagepanel;
    @include background-image(linear-gradient(to bottom, $linkki-color-messagepanel 0%, $linkki-color-messagepanel 100%));
    border: none;
    /* for separating lines between the messages:
    border-color: #ed473b !important;
    */
  }

  .v-panel-content-linkki-message-panel tr{
    background-color: $linkki-color-messagepanel;
    @include background-image(linear-gradient(to bottom, $linkki-color-messagepanel 0%, $linkki-color-messagepanel 100%));
  }
Dynamic style name binding

A new aspect @BindStyleNames has been introduced, to set user defined styles. This will overwrite any other user defined style names but not those from Vaadin. It is possible to provide multiple style names.

@BindStyleNames(type = StyleType.DYNAMIC)
   public String getIcon() {
       return MessageUiComponents.getIcon(message.getSeverity()).getHtml();
   }