Eclipse Scout Migration Guide

About This Document

This document describes all relevant changes from Eclipse Scout 25.1 to Eclipse Scout 25.2. If existing code has to be migrated, instructions are provided here.

The here described functionality has not yet been released and is part of an upcoming release.

Obtaining the Latest Version

Scout Runtime for Java

Scout Runtime artifacts for Java are distributed using Maven Central:

Usage example in the parent POM of your Scout application:

<dependency>
    <groupId>org.eclipse.scout.rt</groupId>
    <artifactId>org.eclipse.scout.rt</artifactId>
    <version>25.1.0-beta.5</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Scout Runtime for JavaScript

Scout Runtime artifacts for JavaScript are distributed using npm:

Usage example in your package.json:

{
  "name": "my-module",
  "version": "1.0.0",
  "devDependencies": {
    "@eclipse-scout/cli": "25.1.0-beta.5",
    "@eclipse-scout/releng": "^25.1.0"
  },
  "dependencies": {
    "@eclipse-scout/core": "25.1.0-beta.5",
    "jquery": "3.7.1"
  }
}

The pre-built Scout JavaScript assets are also available using a CDN (e.g. to be directly included in a html document): https://www.jsdelivr.com/package/npm/@eclipse-scout/core?path=dist

IDE Tooling (Scout SDK)

Scout officially supports IntelliJ IDEA and Eclipse for Scout Developers.

IntelliJ IDEA

You can download the Scout plugin for IntelliJ IDEA from the JetBrains Plugin Repository or you can use the plugins client built into IntelliJ IDEA. Please refer to the IntelliJ Help on how to install and manage plugins.

Eclipse

You can download the complete Eclipse IDE with Scout SDK included here:
Eclipse for Scout Developers

To install the Scout SDK into your existing Eclipse IDE, use this P2 update site:
https://download.eclipse.org/scout/releases

Table: column.sortActive Can Be Removed if sortIndex Is Set (Scout JS)

For Scout JS tables, sortActive is now automatically set to true if sortIndex is >= 0. This means you can remove sortActive: true from your model files if you set a valid sortIndex.

Listing 1. Old
{
  objectType: Column,
  sortActive: true,
  sortIndex: 0
}
Listing 2. New
{
  objectType: Column,
  sortIndex: 0
}

Deprecation of GzipServletFilter and LegacyGzipServletFilter

org.eclipse.scout.rt.server.commons.servlet.filter.gzip.GzipServletFilter and org.eclipse.scout.rt.server.commons.servlet.filter.gzip.LegacyGzipServletFilter have been deprecated and should not be used anymore. Among other things these filters do not support async requests which are used in some parts of the application. If an applications keeps using the deprecated filters a warning will be logged during initialization of these classes.

Instead of these filters the Jetty built-in org.eclipse.jetty.server.handler.gzip.GzipHandler should be used. This handler has been added to the main class org.eclipse.scout.rt.app.Application and is enabled by default.

It may be configured and also disabled using several new configuration properties:

  • scout.app.gzip.enabled: Boolean (default: true); specifies whether the GzipHandler is used

  • scout.app.gzip.excluded.inflate.paths: List of String; excluded inflate paths for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.excluded.methods: List of String; excluded methods for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.excluded.mimeTypes: List of String; excluded MIME types for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.excluded.paths: List of String; excluded paths for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.included.inflate.paths: List of String; included inflate paths for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.included.methods: List of String; included methods for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.included.mimeTypes: List of String; included MIME types for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.included.paths: List of String; included paths for GzipHandler (respected only if at least one is set otherwise Jetty default is used)

  • scout.app.gzip.minSize: Positive integer; minimum size to trigger compression for GzipHandler (respected only if at value is set otherwise Jetty default is used)

  • scout.app.gzip.syncFlush: Boolean (default: true); enables sync flush for GzipHandler

If the application is not run using the recommended main class org.eclipse.scout.rt.app.Application, e.g. for .war deployments the GzipHandler is not registered automatically. For example for a Jetty .war deployment it may be registered by activating the gzip Jetty module.

Switch to the New Data Object API

Scout JS now supports DataObjects to be written as classes in TypeScript. A new serialization mechanisms takes care of recursively (de)serializing such DataObjects in a way compatible with the Scout Java backends. It supports base types like number, string, boolean, but also more complex types like Array, Date, Map, Set or nested Data Objects. Also, TypeScript specific types like Record or string literal types are supported.

It is recommended to switch to the new API where possible by following these steps:

  1. Convert existing DOs (typically declared as TypeScript interfaces extending DoEntity) to classes. The typeName must be declared as Decorator (like Java Annotations but first character lowercase):

    import {BaseDoEntity, typeName} from '@eclipse-scout/core';
    
    @typeName('mynamespace.MyEntity') (1)
    export class MyEntityDo extends BaseDoEntity { (2)
      entityId: string;
      timestamp: Date;
      items: Record<string, MyOtherDo>;
      descriptions: Map<string, DescriptionDo>;
      attachments: AttachmentDo[];
    }
    1 Declare the typeName of the Data Object as decorator. Typically, this is the class name without the Do suffix and must match the @TypeName annotation of the matching Java Data Object class.
    2 Convert to a class extending BaseDoEntity.
  2. If sending or receiving Data Objects to/from the Scout backend migrate the ajax calls to the newly provided convenience methods for Data Objects:

    1. ajax.getDataObject: GET request receiving a Data Object.

    2. ajax.postDataObject: POST request sending and receiving a Data Object.

    3. ajax.putDataObject: PUT request sending and receiving a Data Object.

    4. ajax.removeDataObject: DELETE request sending and receiving a Data Object.

  3. The new (de)serialization mechanism converts most of the data types automatically between its json format and the Data Object class. Therefore, manual conversions (e.g. for Date) can be removed. This includes the use of utilities like JsonValueMapper, objects.parseJson or objects.stringifyJson. Accordingly, these functions have been removed. If custom data types need to be converted, try implementing a DoNodeSerializer in TypeScript and register your new converter in dataObjects.serializers.

  4. As Data Objects are classes now, they can no longer be created as object literals (Pojo). Instead, scout.create should be used:

    import {scout} from '@eclipse-scout/core';
    
    const entityDo = scout.create(MyEntityDo, {
      entityId: '12345',
      ...
    });
  5. To create a shallow copy of a Data Object a new instance must be created as well:

    import {scout} from '@eclipse-scout/core';
    
    const shallowCopy = scout.create(MyEntityDo, {
      ...originalEntityDo,
      additionalPropertyForTheCopy: 'ShallowCopyWillHaveThisAdditionalValue'
    });

    Important: If the spread operator is not the first statement, you need to convert the DO to a Pojo first (.toPojo()), otherwise undefined values from the DO may override actual values. Therefore, it is recommended to always use the original Data Object as the first spread statement.

  6. To create a deep copy of a Data Object use the clone function:

    const deepCopy = originalEntityDo.clone({
      additionalPropertyForTheCopy: 'DeepCopyWillHaveThisAdditionalValue'
    });

    Important: In the (optional) extra model passed to the clone function only primitives and pojos are copied deeply. Complex objects like Date or Map in this extra model are copied by value!

  7. When using the HybridManager or the JsForm: It uses the Data Object class and deserializes to these classes (instead of a Pojo as before) as soon as a class having a matching @typeName decorator is found in TypeScript. So to use the new API for HybridManager or JsForm, just create the necessary Data Object classes. But keep in mind that as soon it is converted, these instances will be returned instead of a Pojo. So this might require some more code migrations on your side (see above).

An example implementation can be found in the REST HowTo.