Documentation Seife for Vaadin Flow

Whats Seife for Vaadin?

The developer tool is a Java compiler enhancement that creates code to bind a Vaadin user interface component to the datamodel of the application. It uses advanced coding idioms to have flexible options when maintaining large code bases or updating large code bases to a new version of Vaadin.

Whats new?

Version 1.8.0 of the framework adds support for read-only Vaadin grid views. Moreover it has cloud functionality to make the meta model available as a .json export for other modules to be used during compilation.
Templates for type-to-form element bindings can be part of your project and allow to create a custom tailored binding that is used whenever a model field matches.
Internally the great performance of the annotation processor has been further improved and additional test-coverage was added.
We have replaced the old licensing module by a more sophisticated asymmetric key system that is easy to use.
Additional examples have been added to the archive that illustrate the new features.

Quick Start

Gradle Configuration

Add the annotation processor as a compile-only dependency to be able to use the sourcelevel annotations e.g. @SeifeField and @SeifeClass. Use the annotationProcessor directive to enable the processing.

repositories {
    mavenCentral()
    maven {
        url "https://repo.uc-mobileapps.com/release"
    }
}

dependencies {
    compileOnly 'com.weebmeister.seife:SeifeAnnotation-vaadin:1.8.0'
    annotationProcessor 'com.weebmeister.seife:SeifeAnnotation-vaadin:1.8.0'
}

compileJava {
    options.compilerArgs << '-Aseife.license.file=' 
           + new File("${projectDir}/license.txt")
    
    options.compilerArgs << '-Aseife.dest.dir=' 
           + new File("${projectDir}/src/main/java")
    options.compilerArgs << '-Aseife.config=' 
           + new File("${projectDir}/seife-local.properties").absolutePath
}

Configure the license by setting the location of the license file, e.g. relative to the project location.
Usually the destination directory is where your sources reside since the toolkit will add code to your UI classes or create packages next to your class. If desired these can be located under /src/main/generated for some types of templates, see the configuration section for further details.

Maven Configuration

The configuration in maven uses the apt-maven plugin to configure the different processor options. Seife’s configuration allows for separate settings if any additional processors are used.

<project [..]>
  <repositories>
    <repository>
      <id>spring-repo</id>
      <url>https://repo1.maven.org/maven2/</url>
    </repository>
    <repository>
       <id>seife</id>
       <url>https://repo.uc-mobileapps.com/release</url>
     </repository>
  </repositories>

  <dependencies>
    <!-- [..] -->
    <dependency>
      <groupId>com.weebmeister.seife</groupId>
      <artifactId>SeifeAnnotation-vaadin</artifactId>
      <version>1.8.0</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
       <plugin>
         <groupId>com.mysema.maven</groupId>
         <artifactId>apt-maven-plugin</artifactId>
         <version>1.1.3</version>
         <executions>
            <execution>
              <goals>
                <goal>process</goal>
              </goals>
              <configuration>
                 <outputDirectory>${project.build.directory}/generated-sources/annotations</outputDirectory>
                 <processors>
                    <processor>com.weebmeister.seife.processor.SeifeProcessor18</processor>
                 </processors>
                 <showWarnings>true</showWarnings>
<options>
  <seife.config>${project.basedir}/seife-config.properties</seife.config>
  <seife.license.file>${project.basedir}/license.txt</seife.license.file>
  <seife.processing.namespaces>vaadin</seife.processing.namespaces>
  <seife.verbose>true</seife.verbose>
  <seife.dest.dir>${project.basedir}/src/main/java</seife.dest.dir>
</options>
              </configuration>
            </execution>
         </executions>
       </plugin>
    </plugins>
  </build>
</project>

When using the apt-maven plugin the standard annotation processing should be disabled in the maven compiler plugin.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
     <compilerVersion>${java.version}</compilerVersion>
     <source>10</source>
     <target>10</target>
     <!-- Disable default annotation processing since apt-maven-plugin takes over -->
     <compilerArgument>-proc:none</compilerArgument>
  </configuration>
</plugin>

A setup with maven or gradle is usually fine, if you prefer to configure the annotation processor with your favorite IDE you can set the options accordingly.

Using the Form template

By setting the generatorOptions to ‘form.formClass’ the template is active for the annotated class. The corresponding model class is referred here as well.

@SpringComponent
@Scope(SCOPE_PROTOTYPE)
@SeifeForm(forClass = Customer.class, generatorOptions = {"form.formClass"})
public class CustomerForm extends FormLayout {

This is enough for the processor to create GUI code for all fields annotated with @SeifeBinding including:

  • code for binding the datafield to the model
  • creation of a unique id for the GUI control
  • check for mandatoryness based on the model

 

Using the Grid template

The read-only grid code template is activated by setting the ‘grid.gridClass’ option in the @SeifeForm annotation.

@SpringComponent
@Scope(SCOPE_PROTOTYPE)
@SeifeForm(forClass = Customer.class, generatorOptions = {"grid.gridClass"})
public class CustomerGrid extends Grid<Customer> {

This allows to easily create bindings for read-only grids immediately from the datamodel. Every @SeifeField annotated attribute Column<Customer> is bound automatically based on the name of the field. It’s a nice convention to have the GUI names and the model attribute names in sync, if this is not possible one can either refer to the model name via @SeifeField(“modelFieldName”) or use the dot-notation to navigate the models’ structure such as “customer.address.street”.

Create custom bindings for datatypes

Suprisingly often the standard implementation in Vaadin does not have a nice conversion of the data to a GUI representation e.g. for the boolean basic datatype.
What you end up doing is creating the binding manually whenever you want to show the model content of the attribute somewhere in the user interface. This is also true for custom types. The probably best example is combined field such as a price with a currency.
These common patterns in can be defined once as a template and then used everywhere the GUI code accesses the model.
The aforementioned template looks like the one below. Once established it is used in all grids that refer to model attributes of type ‘Price’ which not only streamlines your codebase but also reduces the probability of wrong or incomplete code.

${binding.attributeName} = addColumn(TemplateRenderer.<${form.seifeClassModel.className}>of("<div>[[item.price]] [[item.currency]]</div>")
				.withProperty("price",
						entity -> (#propertychain($binding) == null || #propertychain($binding).getValue() == null)
								? "Unavailable"
								: new DecimalFormat("0.00").format(#propertychain($binding).getValue()))
				.withProperty("currency",
						entity -> Optional.ofNullable(#propertychain($binding)).map(p -> p.getCurrency()).orElse("")));

 

Configuration Options

The annotation processor provides several options here is a brief overview that helps setting it up for a project.

 

Advantages of the template based approach

  • Templates can be adjusted to a newer version of Vaadin in just one place and maintenance of outdated code is reduced.
  • Non-repetitive coding experience, developers can focus on the business code instead of writing the same code again in many different but similar contexts.
  • Code that is used in many places is better tested and much more robust to error situations than code that is executed in seldom situations or with a low test coverage.

Frequently asked questions

Are additional libraries needed as runtime dependencies?

No the system is designed to not require any additional libraries in the deployment.

Is the Java reflection API used in the template code?

For the Vaadin form bindings the standard Binder is currently used which relies on reflection. The grid bindings are implemented without reflection, problems usually appear during compile-time and not at runtime.

Available model variables

As already seen in the template example of the custom binding there are several variables that can be used to refer to the model, the form or a property (attribute) of an object.

Below is a list of identifiers and to which type they refer. The API-Docs contained in the archive has the technical informations for it.

Projection Templates
  • model
    refers to SeifeClassModel
  • form
    refers to SeifeFormModel
  • properties
    models with properties expose this variable as a list of SeifePropertyModel
Aggregation Templates
  • models
    aggregating templates can use this list of SeifeMergeConfigurationModel instances that refer to each aggregated model
  • modelClasses
    set of aggregated fully qualified names of the models from above
  • serviceModel
    Aggregates information for classes that combine functionality of several class models such as services