Eclipse Scout Migration Guide

This document is referring to an upcoming Scout release. Please click here for the current version.

About This Document

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

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>26.1.0-beta.1</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": "26.1.0-beta.1",
    "@eclipse-scout/releng": "^26.1.0"
  },
  "dependencies": {
    "@eclipse-scout/core": "26.1.0-beta.1",
    "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

New Build & Runtime Requirements

Scout 26.1 requires at least the following:

  • Build and runtime of Scout 26.1 require Java 25. The compiler target level is set to Java 21.

  • Furthermore, the build requires

    • Node: >= 24.12.0

    • Pnpm: >= 10.26.1

Action / Menu: Tabbable Default Changed (Scout JS)

An Action and a Menu is now tabbable and has a keystroke to execute it by default. This means if you used an action or a menu outside a menu bar, it can now get the focus using the keyboard. This is important to improve the accessibility of your application.

However, there may be some actions or menus that should not be tabbable. In that case just set tabbable to false.

WidgetField: Scrollable Default Changed (Scout JS)

A WidgetField has a property scrollable whose default value is true. This is often not desired as a WidgetField is supposed to be a wrapper for a widget without changing its behavior. This is why the default value has been changed to false.

So you need to check your widget fields if they really need to be scrollable and if yes set scrollable to true. Normally, this should not be the case as a surrounding container like the main box is already scrollable.

Switch: Tabbable Default Changed (Scout JS)

A Switch is now tabbable by default. This is important to improve the accessibility of your application.

However, there may be some switches that should not be tabbable. In that case just set tabbable to false.

Code Cleanup

JQuery-Scout (Scout JS)

The following functions have been renamed:

  • select(boolean) → setSelected(boolean)
    If you followed the naming convention, you can use the following regex to find the occurrences: \$\w+\.select\(
    Note: select() also exists on an HTMLInputElement, so make sure you don’t accidentally rename the wrong method (if you use TypeScript the compiler will help you).

The following functions have been removed:

  • selectOne()
    Replace with setSelected(true) and setSelected(false) on the siblings.

Widget.cssClass: API Changes (Scout JS)

The methods to modify the cssClass property of the Widget were moved to the styles utility (see Release Notes). The API of setCssClass, addCssClass, removeCssClass, toggleCssClass and hasCssClass remains the same but the method cssClassAsArray and the static method cssClassAsArray were removed. Code using these methods must be migrated as follows:

Listing 1. old: using the cssClassAsArray methods of the Widget.
const widget = scout.create(Widget, {
  // ...
  cssClass: 'foo bar'
});
const widgetCssClassAsArray = widget.cssClassAsArray();

const cssClass = 'foo bar';
const cssClassAsArray = Widget.cssClassAsArray(cssClass);
Listing 2. new: using the cssClassAsArray methods of the styles utility.
const widget = scout.create(Widget, {
  // ...
  cssClass: 'foo bar'
});
const widgetCssClassAsArray = styles.cssClassAsArray(widget.cssClass);

const cssClass = 'foo bar';
const cssClassAsArray = styles.cssClassAsArray(cssClass);

widgets Util: Behavior Change of preserveAndSetProperty (Scout JS)

If you use the function widgets.preserveAndSetProperty in your JavaScript code, please make sure that the variable that stores the preserved value is not initialized or initialized to undefined. If it is initialized to null, remove the initialization.

Service tunnel: Servlet removed, REST resource added

In the past the service tunnel used its own servlet/communication implementation to transfer data between client and server module. The own (proprietary) logic was removed and standard REST communication will be used for data transfer now.

Most applications should not be affected by these changes as for the outside the service tunnel should still function the same way it did previously (most changes are under the hood).

However, for further understanding a few changes included in this change are described here:

The service tunnel client (e.g. HttpServiceTunnel) has been moved from org.eclipse.scout.rt.shared to org.eclipse scout.rt.client; in the past it would have been possible to use the service tunnel for communication between backend servers, this is not possible anymore. As the class now resides in the client the ClientHttpServiceTunnel has been integrated into the HttpServiceTunnel.

The HttpServiceTunnel does not send the outgoing HTTP request itself anymore, instead a newly created ProcessResourceClient (REST resource client) is used. This resource client uses the newly added ScoutBackendRestClientHelper for configuration. The HttpServiceTunnelTransportManager and its configuration properties scout.servicetunnel.maxConnectionsPerRoute and scout.servicetunnel.maxConnectionsTotal have been removed.

On the server-side there is no ServiceTunnelServlet anymore to answer incoming HTTP requests, instead a ProcessResource (REST resource) has been created which delegates the request to the ServiceTunnelService.

Arbitrary IServiceTunnelContentHandler support was removed (and also the SoapServiceTunnelContentHandler implementation), the service tunnel now always uses the BinaryServiceTunnelContentHandler bean (which may still be extended).

The duplicate request detection SequenceNumberDuplicateDetector has been removed.

By default, the service tunnel uses gzip compression for outgoing and incoming requests, this may be configured using the following configuration properties:

  • scout.servicetunnel.compress: Specifies if the service tunnel should use gzip compression for outgoing requests (default: true)

  • scout.app.gzip.inflateBufferSize: Set a positive number to enable incoming compressed requests (default: 2048), positive number must be set if previous property is set to true

For outgoing request compression the org.glassfish.jersey.message.GZipEncoder is installed (by the GzipEncoderContributor, it handles content-encoding possibly set by ProcessResourceClient). Incoming request decompression and outgoing response compression is handled by the org.eclipse.jetty.compression.server.CompressionHandler with org.eclipse.jetty.compression.gzip.GzipCompression. The response decompression (if applicable) is handled by the HTTP client org.apache.hc.client5.http.entity.DecompressingEntity.

Applications which are deployed using a web.xml to a Jetty (legacy) may need to add the compression-gzip module. Also, the process servlet and its mapping must be removed from the web.xml.

The following configuration properties have been changed:

  • server.url (legacy): Removed, use scout.backendUrl instead.

  • scout.servicetunnel.targetUrl: Removed, use scout.backendUrl instead.

  • scout.backendUrl: Moved from shared to client code (not applicable for server backend application anymore)

  • scout.createTunnelToServerBeans: Moved from shared to client code (not applicable for server backend application anymore)

For all REST requests the cancellation behavior has been changed, previously a cancel request was sent and the client did wait (blocking) for the backend request to be cancelled. Now the same cancel request is sent to the backend which tries to cancel the possibly running request, but the client-side also aborts the running request itself without waiting for any cancellation response allowing the user to interact quicker with the application again (same behavior as previously in service tunnel).

DefaultAuthToken: Package changed, constant moved

As the DefaultAuthToken was not used exclusively for the service-tunnel the following types and constants have been moved:

Type/Constant Target

org.eclipse.scout.rt.shared.servicetunnel.http.DefaultAuthToken

org.eclipse.scout.rt.shared.authentication.DefaultAuthToken

org.eclipse.scout.rt.shared.servicetunnel.http.DefaultAuthTokenPrincipalProducer

org.eclipse.scout.rt.shared.authentication.DefaultAuthTokenPrincipalProducer

org.eclipse.scout.rt.shared.servicetunnel.http.DefaultAuthTokenSigner

org.eclipse.scout.rt.shared.authentication.DefaultAuthTokenSigner

org.eclipse.scout.rt.shared.servicetunnel.http.DefaultAuthTokenVerifier

org.eclipse.scout.rt.shared.authentication.DefaultAuthTokenVerifier

org.eclipse.scout.rt.shared.servicetunnel.http.HttpServiceTunnel#TOKEN_AUTH_HTTP_HEADER

org.eclipse.scout.rt.shared.authentication.DefaultAuthToken#HTTP_HEADER_NAME

Session API changes

As part of the move toward a stateless backend server, the API of the session has been changed.

ISession:

  • getSharedVariableMap moved to the IClientSession.

  • getUserId moved to the IClientSession. On server, use the ThreadLocal UserId.CURRENT instead.

IClientSession:

  • replaceSharedVariableMapInternal removed. To update variables on the client session use setSharedVariables or send a SharedContextChangedNotification from the backend.

AbstractServerSession:

  • m_sharedVariableMap removed. No more data should be stored on the server session. The data should be stored in user-based caches or loaded from the database instead. To add additional variables during client session initialization, implement an IInitialSharedVariableContributor.

AbstractClientSession:

  • initializeSharedVariables renamed to loadInitialSharedVariables.

ServiceTunnelRequest:

  • getSessionId removed. Replaced by a custom HTTP Header X-Scout-Client-Session-Id.

  • setSessionId removed. Replaced by a custom HTTP Header X-Scout-Client-Session-Id.

User Preferences Moved from Shared to Client

As part of the move toward a stateless server session, IPreferences, IUserPreferencesService, IUserPreferencesStorageService, IPreferenceChangeListener and their corresponding implementations have been moved from shared to client.

If you use these classes you need to adjust your import statements.

Data Object Serializer Provider Implementations Supplemented with Order Annotation

The Scout implementation ScoutDataObjectSerializerProvider of serializer/deserializer provider interface IDataObjectSerializerProvider was supplemented with an @Order annotation using value 4500 to achieve a fixed order when looking up all instances by BEANS.all(IDataObjectSerializerProvider.class).

ACTION: Check custom implementations of IDataObjectSerializerProvider interface. Default order for bean implementations without @Order annotation is 5000, which means your IDataObjectSerializerProvider is invoked as last instance. Usually this is appropriate if your implementation just adds serializer or deserializers for additional classes.

If you want to override any Scout serializer/deserializer use an order lower than 4500 for your implementation and become the first provider which is invoked.

Simple tab box (Scout JS)

The SimpleTabBox has been improved and can now display the tabs on any side of the box. As part of these adjustments, the associated SimpleTabAreaLayout has been modified and attributes have been renamed.

  • tabWidth was renamed to tabSize

  • tabMinWidth was renamed to tabMinSize

  • overflowTabItemWidth was renamed to overflowTabItemSize

SearchOutline (Scout Classic)

The SearchOutline now works for both Scout Classic and Scout JS pages (see Release Notes). With this the property searchStatus was removed as it may no longer be updated manually. Pages that need to add information to the searchStatus may simply implement ISearchPage and update their provided ISearchState with information about the result count, whether the result is limited or the search is still pending. The SearchOutline will collect all these information and build an aggregated searchStatus.

JUnit: Runtime assertion for PlatformTestRunner

A new default runtime assertion has been added to the PlatformTestRunner.

If a test method exceeds a specific runtime duration it is still completed but fails afterward (allowing to easier identify unwanted long-running successful tests).

The default runtime limit is set to three minutes. The limit may be increased by setting a higher timeout on the @Test annotation. The limit is disabled completely when a negative timeout is set on the @Test annotation.

Removed automatic binding for session variables in SQL statements

Previously, SQL queries could reference session variables as bind parameters without explicitly providing their values. For example:

SELECT :userId;

In this case, the :userId bind was automatically populated from the current session context.

What Changed: Automatic binding of session variables to SQL bind parameters has been removed. Queries now require explicit binding of the session variables during execution.

For compatibility reasons the userId bind is still automatically bound with the current user id. But all the other session variables are not automatically bound anymore.

Action Required: Review and update your queries to explicitly bind the session variables when executing SQL statements.

ApiRestApplication: Mark external accessible REST operations

A new ApiExposedFilter has been created to distinguish between internal and external (proxied) requests, it is installed automatically by the ApiApiExposedFeature for the ApiRestApplication (feature is annotated with @RestApplicationScope(RestApplicationScopes.API) hence ExtRestApplication will ignore it).

All REST operations (methods) available through ApiRestApplication (for all resources)

  • which are accessed externally using an AbstractRestProxyRequestHandler (accessed from scripts run by the browser) should be marked with @ApiExposed to keep them accessible (either the resource method or the whole class).

  • which are only used internally between applications (not accessed externally) may optionally be marked with @ApiExposed(false).

ESLint Update

Scout updated to the latest version of ESLint. Because ESLint changed their config file format, you need to adjust your ESLint files.

  1. Rename .eslintrc.js to eslint.config.mjs

  2. Rewrite the content according to the Scout archetype

  3. Add the exclusions from .eslintignore and remove that file (**/node_modules is ignored by default and doesn’t need to be added)

Listing 3. Example eslint.config.mjs
import {defineConfig, globalIgnores} from 'eslint/config';
import scoutConfig from '@eclipse-scout/eslint-config';

export default defineConfig([
  scoutConfig,
  globalIgnores([
    '.git',
    '.idea',
    '*/dist',
    '*/target',
    '*/src/main/resources',
    '*/src/test/resources',
    '*/src/main/java',
    '*/src/test/java'
  ])
]);

ESLint Rule Deprecation

ESlint deprecated their formatting rules and moved them to a plugin called @stylistic. Scout now uses this plugin, so the existing rules still apply.

This impacts you if you have a customized ruleset in eslint.config.mjs or if you have eslint-disable or eslint-disable-next-line directives in your code. In either case, just prefix the deprecated rule names with @stylistic. The easiest way to find these issues is to run eslint . in your workspace.

Example migration:

Listing 4. Old
/* eslint-disable brace-style */
// eslint-disable-next-line max-len
Listing 5. New
/* eslint-disable @stylistic/brace-style */
// eslint-disable-next-line @stylistic/max-len

For more details about the deprecation please consult the official ESLint announcement.

HTTP Cache Control

In the past the following call was used to disable caching for an HTTP response: HttpCacheControl.checkAndSetCacheHeaders(req, resp, null). This can now be changed to the more readable variant as the underlying method is public now: HttpCacheControl.disableCaching(resp).

The new function BEANS.get(HttpCacheControl.class).disableCaching(response) can also be used to replace the old pattern of manually setting the HTTP response headers:

response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);

Hardening the Content Security Policy

The Content Security Policy used by Scout applications has been hardened. It now makes use of nonces for JavaScript which may prevent cross-site scripting attacks. Nonces are only used for script tags. style or link tags used for CSS are not affected.

API Changes

  • The bean org.eclipse.scout.rt.server.commons.servlet.ContentSecurityPolicy has been moved to org.eclipse.scout.rt.security.csp.ContentSecurityPolicy and is therefore more widely available.

    Furthermore, it changed its meaning: In the past it was a builder that was prefilled with the Scout defaults, adapted by your config.properties settings. This is no longer the case. This class represents only a builder now and starts empty on creation.

    Please note: an empty CSP does not mean everything is blocked. Instead, not configuring a directive means: all allowed! Therefore, it is recommended to replace the former ContentSecurityPolicy class with the new ConfigurableContentSecurityPolicy or BlockAllContentSecurityPolicy class (see below).

  • New bean org.eclipse.scout.rt.security.csp.ConfigurableContentSecurityPolicy which replaces the old ContentSecurityPolicy class. It is still preloaded with the same Scout default directives which still can be adapted in your config.properties.

  • New bean org.eclipse.scout.rt.security.csp.BlockAllContentSecurityPolicy which by default blocks all. It can be used as starting point to create a policy as restrictive as possible, by selectively opening directives.

  • The CSP ConfigProperty classes have been moved from org.eclipse.scout.rt.server.commons.ServerCommonsConfigProperties to org.eclipse.scout.rt.security.csp.ContentSecurityPolicyConfigProperties.

  • org.eclipse.scout.rt.server.commons.servlet.HttpServletControl.HTTP_HEADER_CSP has been moved to org.eclipse.scout.rt.security.csp.ContentSecurityPolicy.HTTP_HEADER.

  • org.eclipse.scout.rt.server.commons.servlet.HttpServletControl.CSP_REPORT_URL has been moved to org.eclipse.scout.rt.security.csp.ContentSecurityPolicy.REPORT_URL.

  • org.eclipse.scout.rt.server.commons.servlet.HttpServletControl.HTTP_HEADER_CSP_LEGACY has been removed as it was only used by legacy browsers no longer supported.

Content Security Policy Migration

  • Responses to REST resources now include a BlockAllContentSecurityPolicy by default. This prevents possible attacks if the response is of type text/html, image/svg or text/javascript (which would be interpreted by a browser).

    If you need REST responses to be interpreted by the browser, you have to apply your own CSP header with your rules to the response. If the header is already present, the default header is not added.

  • If you manually (without using $.injectScript) load new JavaScript code: Consider migrating to $.injectScript or add the nonce attribute where necessary. The current value can be retrieved on the Scout App: App.get().nonce.

  • If you use an AbstractHtmlField or AbstractHtmlTile that contains inline JavaScript code, these script tags require the nonce attribute to be executed.

    The value can be obtained:

    • In Scout Classic by using org.eclipse.scout.rt.shared.ui.webresource.SessionNonce.provide().

    • In Scout JS from the App: App.get().nonce.

    • In the JSON layer from the UiSession: org.eclipse.scout.rt.ui.html.IUiSession.getNonce().

  • 'unsafe-inline': If you did use the CSP expression 'unsafe-inline': This expression is ignored by browsers if nonces are used. Therefore, this CSP expression can be removed. Instead, add the nonce attribute to your inline script tags as described above.

  • External script tags in your entrypoint html files: If you use hardcoded script tags in your entrypoint html files (instead of using scout:scripts e.g. to point to an external script), add the following attribute: nonce="scout:nonce". This expression will then be replaced with the correct nonce automatically.

New Features

  • If you load content to AbstractBrowserField by using a BinaryResource: Until now the CSP of the resources loaded into the BrowserField used the same CSP as the Scout application itself (this is still the case, but as the policy is more restrictive now, scripts from the Scout server are no longer automatically accepted).

    Now you have more control: The AbstractBrowserField now allows configuring the CSP for each instance and resource. It is recommended to use specific CSP rules for such fields which should be as restrictive as possible.

    As a starting policy the new BlockAllContentSecurityPolicy could be used and then opening directives as necessary. The created policies can be applied to a field in e.g. the execInitField method by using the following methods:

    • setContentSecurityPolicy: One CSP for the whole field (all resources of the field).

    • putContentSecurityPolicy: A CSP for a specific resource of the field.

  • The ConfigurableContentSecurityPolicy is more flexible now. It is recommended to harden your CSP with these new features:

    • As in older releases it can still be configured using the config property scout.cspDirective. Directives added to this property completely replace the hard-coded directive coming from the Scout defaults and should be configured as minimal as possible (same as in older releases).

    • A second config property scout.cspDirectiveAppend was added. Its directives do not replace but append instead. It may append to the Scout defaults (if nothing is configured) or to the ones configured using scout.cspDirective.

      This allows to e.g. set some always-valid directives in the scout.cspDirective property within the config.properties file and then adding more expressions to a directive e.g. using an environment variable for specific installations.

    • For both properties it can be specified for which html entry point the directive is valid by using a suffix. Example:

      # directive valid for all entry points
      scout.cspDirective[script-src]=https://my.cdn.org/
      
      # additional url only for login.html
      scout.cspDirective[script-src#login.html]=https://login.cdn.org/

    To set this value as environment variable it is required to use the JSON synthax as explained in the Technical Guide.

  • If you need to change the response of a resource (e.g. to finetune its CSP response header), the new interface org.eclipse.scout.rt.ui.html.res.loader.WebResourceLoader.IWebResourceResponseInterceptorContributor can be implemented. Such contributors are called for each web resource loaded and return a list of org.eclipse.scout.rt.server.commons.servlet.cache.IHttpResponseInterceptor for a request. These interceptors are then called before sending the response to the client. You can e.g. identify a request with responseObject.getCacheKey().getResourcePath().