- 1.2.55
- 1.2.54
- 1.2.53
- 1.2.52
- 1.2.51
- 1.2.50
- 1.2.49
- 1.2.48
- 1.2.47
- 1.2.46
- 1.2.45
- 1.2.44
- 1.2.43
- 1.2.42
- 1.2.41
- 1.2.40
- 1.2.39
- 1.2.38
- 1.2.37
- 1.2.36
- 1.2.35
- 1.2.34
- 1.2.33
- 1.2.32
- 1.2.31
- 1.2.30
- 1.2.29
- 1.2.28
- 1.2.27
- 1.2.26
- 1.2.25
- 1.2.24
- 1.2.23
- 1.2.22
- 1.2.21
- 1.2.20
- 1.2.19
- 1.2.18
- 1.2.17
- 1.2.16
- 1.2.15
- 1.2.14
- 1.2.13
- 1.2.12
- 1.2.11
- 1.2.10
- 1.2.9
- 1.2.8
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
Overview of Ballerina Swan Lake Alpha1
This Alpha1 release includes the language features planned for the Ballerina Swan Lake release. Moreover, this release includes improvements and bug fixes to the compiler, runtime, standard library, and developer tooling. This release note lists only the features and updates added after the eighth preview of Ballerina Swan Lake.
- Updating Ballerina
- Highlights
- What is new in Ballerina Swan Lake Alpha1
- Language
- Intersection type support for errors
- Support for passing a closed record as the rest argument
- Support for the empty XML value
- Improvements to the match statement
- Support for cyclic union types
- Updated syntax for user-defined error construction
- Changes to casting with errors
- Changes to
toString
andtoBalString
with errors - Changes to object type inclusion with qualifiers
- Changes to record type inclusion with rest descriptors
- Improved listener declaration
- Referring lang library modules without using quoted identifiers
- Improved lang library methods
- Packages
- Runtime
- Developer tools
- Standard library
- HTTP module improvements
- WebSocket module improvements
- gRPC module improvements
- Security improvements
- GraphQL module improvements
- TCP module improvements
- UDP module improvements
- Common changes in messaging modules
- Kafka module improvements
- NATS module improvements
- NATS streaming module improvements
- RabbitMQ module improvements
- Time module improvements
- Rename system module to OS
- Runtime module improvements
- Email module improvements
- WebSub module improvements
- Introduced new modules
- Removed modules
- Code to Cloud
- Observability
- Breaking changes
- Taint analyzer update
- Language
Updating Ballerina
You can use the update tool to update to Ballerina Swan Lake Alpha1 as follows.
For existing users
If you are already using Ballerina, you can directly update your distribution to the Swan Lake channel using the Ballerina update tool. To do this, first, execute the command below to get the update tool updated to its latest version.
ballerina update
From now onwards, the ballerina
command has to be issued as bal
. Next, execute the command below to update to Swan Lake Alpha1.
bal dist pull slalpha1
However, if you are using a Ballerina version below 1.1.0, install via the installers.
For new users
If you have not installed Ballerina, then download the installers to install.
Highlights
- Support for intersection types with errors
- Support for more match patterns in the match statement
- Support for cyclic union type descriptors
- Changes to casting and
toString
/toBalString
with errors - Changes to object-type and record-type inclusions
- Improved listener declaration
- The
ballerina
command has been renamed tobal
- Introduction of hierarchical package names
- Introduction of the
Dependencies.toml
file - Introduction of REPL support for Ballerina via the
bal shell
command - Improvements to developer tools such as the Language Server, Project API, Debugger, Test Framework, Bindgen tool, Maven Resolver, and Documentation
- Improvements to the HTTP, WebSocket, gRPC, security, GraphQL, Kafka, NATS, NATS Streaming, RabbitMQ, Time, Runtime, Email, and WebSub standard library modules
- Introduction of the new Random, RegEx, TCP, UDP, and WebSubHub standard library modules
- Code action and code completion support for Code to Cloud libraries in the VS Code plugin
What is new in Ballerina Swan Lake Alpha1
Language
Intersection type support for errors
Intersection types are now allowed with error
types. An error
value will belong to the intersection type (E1 & E2
) only if it belongs to each member error type (E1
and E2
) of the intersection.
type InvalidCodeError error<record { int code; }>; type UnavailableError error<record { string[] alternatives; }>; type Error error<record { int code; string[] alternatives; boolean fatal; }>; public function main() { Error err = error Error("InvalidCode", code = 1234, alternatives = ["ballerina.io"], fatal = true); // Since `Error` is a subtype of both `InvalidCodeError` and `UnavailableError` // it is a subtype of the intersection type of `InvalidCodeError` and `UnavailableError`. // Thus `err` can be assigned to a variable of type `InvalidCodeError & UnavailableError`. InvalidCodeError & UnavailableError intersection = err; }
Support for passing a closed record as the rest argument
A closed record can be used as the rest argument in a function or method call. This is the same as passing each field in the record value as a named argument.
import ballerina/io; type SalaryDetails record {| int annualIncrement = 20; float bonusRate?; |}; function printSalaryDetails(int baseSalary, int annualIncrement, float bonusRate = 0.02) { io:println("Base Salary: ", baseSalary, " | Annual Increment: ", annualIncrement, " | Bonus Rate: ", bonusRate); } public function main() { SalaryDetails details = { annualIncrement: 30, bonusRate: 0.03 }; // Same as `printSalaryDetails(2500, annualIncrement = 30, bonusRate = 0.03);` printSalaryDetails(2500, ...details); details = {}; // Same as `printSalaryDetails(2500, annualIncrement = 20);` printSalaryDetails(2500, ...details); }
Support for the empty XML value
Previously, it was possible to define a value of type xml<never>
(i.e., the empty XML value) only using the concat
XML lang library method.
xml<never> emptyXmlValue = <xml<never>>'xml:concat();
It is now possible to directly create the empty XML value.
xml<never> emptyXmlValue = xml ``;
Improvements to the match statement
Support for more match patterns
List match pattern
match v { var [a, b] => { // Matches lists with 2 elements. } var [a, [b, c], d]|var [a, b , c, d] => { // Matches // - lists with 3 elements where the second element is a list of 2 elements or // - lists with 4 elements } }
Mapping match pattern
match v { {a: "hello", b: "world"} => { // Match mappings that contain the field `a` with // value "hello" and field `b` with value "world". } {a: var x} => { // Match mappings that contain the field `a`. // The value is assigned to the variable `x` // and can be assigned within the block. io:println(x); } }
Error match pattern
match v { error ("Message") => { // Match errors with "Message" as the error message. } error () => { // Match all errors. } }
Improved type narrowing within match statements
When code is executed through each match-clause, the type of the matched expression is narrowed. In the example below, the type of v
in the last match clause is narrowed to string
.
function getString(boolean|int|string v) returns string { match v { var a if a is int|boolean => { return a.toString(); } _ => { return v; // Type of `v` is `string` here. } } }
Support for cyclic union types
Cyclic union types are now supported. A cyclic union type descriptor can directly refer to its identifier in its type descriptor.
type Integers int|Integers[]|map<Integers>; Integers intValue = 5; Integers intArray = [1, 2, 3, 4]; Integers intMap = {i: 1, j: 2}; Integers integers = [intValue, intArray, intMap];
Updated syntax for user-defined error construction
The error constructor expression now requires the error
keyword to construct a user-defined error.
Previous syntax:
MyError myError = MyError("Message");
New syntax:
MyError myError = error MyError("Message");
Changes to casting with errors
Errors cannot be cast away (i.e., if the value that is being cast can be an error, the type to which the cast is attempted should also have a subtype of error).
The following was allowed previously.
function foo() returns string|int|error { return error("Error Message"); } public function main() { string s = <string>foo(); // Cast without considering the error. }
This is now disallowed and can be rewritten as follows.
-
Using
checkpanic
- This will preserve thepanic
behavior (but with a different error - the previous error was a cast error. Now, it will be the actual error returned byfoo()
).function foo() returns string|int|error { return error("Error Message"); } public function main() { // Use`checkpanic` to panic if `foo()` returns an error and then attempt the cast. string s = <string>checkpanic foo(); }
-
Using
check
- Alternatively, if the function’s return type allows returning the error,check
can be used before attempting the cast to return the error instead of panicking.function foo() returns string|int|error { return error("Error Message"); } public function main() returns error? { // Use`check` to return the error if `foo()` returns an error, and then attempt the cast. string s = <string>check foo(); }
Changes to toString
and toBalString
with errors
It was previously possible to call toString()
and toBalString()
on unions of errors and non-errors.
function print(any|error val) { string s = val.toString(); }
This has now been disallowed and the error scenarios need to be handled explicitly. The above example can be rewritten as follows.
function print(any|error val) { string s = val is error ? val.toString() : val.toString(); }
Changes to object type inclusion with qualifiers
- When object type inclusion is used with an object type descriptor with qualifiers (
isolated
,client
,service
), it is now mandatory for the object in which the inclusion is done to also have these qualifiers. - Object type descriptors can no longer use object type inclusion with
readonly
classes. - Classes can use object type inclusion with
readonly
classes only if the including classes themselves arereadonly
classes. - The type reference in an object constructor expression can refer to a
readonly
class only if the object being constructed isreadonly
.
Changes to record type inclusion with rest descriptors
Record type inclusion now copies the rest descriptor from the included type to the including type. The including type may override the rest descriptor.
type Configuration record {| int id; decimal...; |}; type DefaultConfiguration record {| // The rest descriptor is also copied. *Configuration; boolean active; |}; DefaultConfiguration config = { id: 1000, active: true, // Additional fields of type `decimal` can be specified since the rest descriptor // is copied from `Configuration`. "factor": 1.0, "index": 0.0 };
The rest descriptor of the DefaultConfiguration
is of type decimal
.
type Configuration record {| int id; decimal...; |}; type InclusiveConfiguration record { // Since `InclusiveConfiguration` is an inclusive record type descriptor the // `anydata` rest descriptor overrides the rest descriptor from `Configuration`. *Configuration; boolean active; }; InclusiveConfiguration inclusiveConfig = { id: 1002, active: true, // Additional fields of type `anydata` can be specified since the rest descriptor // is overridden as `anydata`. "factor": 1.0, "owner": "admin" }; type ExclusiveConfiguration record {| // The record type descriptor of `ExclusiveConfiguration` overrides the rest // descriptor from `Configuration`, making the rest descriptor of `ExclusiveConfiguration` // be of type `boolean`. *Configuration; boolean active; boolean...; |}; ExclusiveConfiguration exclusiveConfig = { id: 1003, active: false, // Additional fields of type `boolean` can be specified since the rest descriptor is overridden. "allow": true };
The rest descriptor type of the InclusiveConfiguration
is anydata
and that of the ExclusiveConfiguration
is boolean
. The including records override the rest descriptor from the included record.
Improved listener declaration
The listener declaration is improved to allow using listener classes that may return an error on initialization. This allows the following listener declaration where the init
method of Listener
may return an error.
listener lsn = new Listener();
Before this change, listener
authors had to use panic
in the init
method instead of returning an error if the listener
object failed to initialize.
If the initialization of the listener object returns an error, module initialization will fail.
listener lsn = new Listener(); public class Listener { public isolated function 'start() returns error? { } public isolated function gracefulStop() returns error? { } public isolated function immediateStop() returns error? { } public isolated function detach(service object {} s) returns error? { } public isolated function attach(service object {} s, string[]|string? name = ()) returns error? { } public function init() returns error? { ... // Return an error if initialization failed due to some reason. if (objectInitFailed) { return error("Listener initialization failed"); } } }
Previous syntax:
listener lsn = new Listener(); public class Listener { ... ... // listener life cycle methods public function init() { ... // object init failed due to some reason if (object_init_failed) { panic error("Listener initialization failed"); } } }
Referring lang library modules without using quoted identifiers
Lang library module prefixes can now be used without the initial quote. For example, both the approaches below are now supported.
int a = int:sum(1, 2);
int a = 'int:sum(1, 2);
Improved lang library methods
Introduction of the includes
method
A new lang library method named includes
, which tests whether a string
value includes another string
value has been added to the ballerina/lang.string
library. It accepts an optional second argument to indicate the index to start searching from. It returns true
only if the string contains the other string at an index greater or equal to the start index. The value false
will be returned otherwise.
string str = "Ballerina Programming Language"; boolean includes = str.includes("Language", 10);
Introduction of the sleep
method
A new sleep
method, which pauses the execution of the current strand for a specified time in seconds has been added to the ballerina/lang.runtime
library.
runtime:sleep(2.0);
Introduction of the getStackTrace
method
A new getStackTrace
method has been introduced in the ballerina/lang.runtime
library to get a stack trace for the current call stack for the specified execution point. It returns an array of stack frames.
runtime:StackFrame[] stackFrames = runtime:getStackTrace();
Introduction of the Cloneable
type
A new type named Cloneable
has been introduced to the ballerina/lang.value
library. This is a cyclic union type. This type represents the values on which clone
and cloneReadOnly
can be applied on.
public type Cloneable readonly|xml|Cloneable[]|map<Cloneable>|table<map<Cloneable>>;
Rename of the ballerina/java
module
The ballerina/java
module is renamed to ballerina/jballerina.java
.
Packages
Introduction of hierarchical package names
Now, the package name can take the form of package-name := identifier(.identifer)*
meaning the dot (.
) is allowed in the package name.
The following is a valid Ballerina.toml
file.
[package] org = "ballerinax" name = "observe.prometheus" version = "1.0.0"
Introduction of the dependencies TOML file
This is a dedicated file to maintain all the dependencies, which is expected to be created in the package root directory. All the dependencies which were previously declared in the Ballerina.toml
file should be moved to this file now.
A valid Dependencies.toml
file will be as follows.
[[dependency]] org = "ballerina" name = "io" version = "0.5.5" [[dependency]] org = "ballerina" name = "log" version = "1.0.5"
Support to accept an empty Ballerina TOML file
A valid Ballerina package can now contain an empty Ballerina.toml
file. This makes it easier to convert an application/service written in a standalone Ballerina file to a Ballerina package.
Runtime
New APIs are added for creating immutable Ballerina records and arrays from Java.
The new ValueCreator.createReadonlyArrayValue
API creates a new readonly
Ballerina array from the given Java array and the ValueCreator.createReadonlyRecordValue
creates a new readonly
Ballerina record.
Configurable
The configurable
feature is improved to support variables with decimal and arrays of int
, float
, string
, boolean
, and decimal
types.
For example if the Config.toml
file contains the following arrays,
ints = [1,2,3] strings = ["red", "yellow", "green"]
they can be loaded as follows.
configurable int[] & readonly ints = ?; configurable string[] & readonly strings = ?;
Configurations can be provided at runtime using the Config.toml
file in the current working directory or by exporting the file path using the BALCONFIGFILE
environment variable. For the tests, configurations can be overridden by having a Config.toml
file inside the tests directory.
Developer tools
Language Server
Find all Reference
Support- CodeLens support for
DocumentThis
is available to auto-generate documentation for public documentable constructs - CodeAction for
ChangeVariableType
is available to solve incompatible variable assignments
Project API
TOML and MD files are made a part of the Project API.
Debugger
- Enhanced table variable presentation with the support to view child entries
- Introduced type test expression evaluation support
Test framework
Support for function pointers in the @test:Config {}
annotation. The fields before
, after
, dependsOn
and dataProvider
, which previously expected the name of the function as a string
, now accept function pointers instead.
Bindgen tool
Introduced a -m|--modules
flag to generate module-level mappings for Java packages generated using the Bindgen tool.
Maven resolver
Introduced support for specifying custom Maven repositories in the Ballerina.toml
file. The configuration below can be used for this purpose.
[[platform.java11.repository]] id = "<maven-repository-id>" url = "<maven-repository-url>" username = "<github-username>" password = "<github-PAT>"
Ballerina Shell REPL [EXPERIMENTAL]
Introduced Read-Evaluate-Print-Loop (REPL) support for Ballerina, which can be accessed via the bal shell
command. Shell runs a REPL instance of Ballerina to enable running snippets of code. An example shell session is shown below:
> bal shell Welcome to Ballerina Shell REPL. Type /exit to exit and /help to list available commands. =$ any a = 10 =$ a is int =$ function add(int x, int y) returns int => x + y =$ add(3, 4) 7 =$ /exit | Bye!!!
Documentation
Now, documentation URLs follow the orgName/packageName/version/moduleName
structure.
Standard library
HTTP module improvements
Allow multiple return types for the resource method
The resource
method can return anydata type, an http:Response
object, StatusCode
records along with error?
. Instead of using an http:Caller
, the response can be sent similarly by returning from the method.
When returning anydata, the @http:Payload
annotation can be used to specify the content type of the response additionally. Otherwise, the default content type of the respective return value type will be added.
service on new http:Listener(8080) { resource function get hello () returns string { return "Hello"; // Content type defaults to `text/plain` } resource function get goodbye () returns @http:Payload {mediaType: "text/plain+id"} string { return "\"Goodbye!\""; } }
Introduce status code response records
With the introduction of records for the most commonly used status codes, the response can be sent inline.
service on helloEP { resource function get hello () returns http:Ok? { return {body: "Hello world", headers: {"x-test": "123abc"}, mediaType: "text/plain"}; } }
Introduce the response limit configuration
The http:Client
facilitates validations on inbound responses based on size limits. Each response that exceeds the limits will be returned as an error.
http:Client clientEP = new ("http://localhost:9092/hello", config = {responseLimits: { maxStatusLineLength: 50, maxHeaderSize: 1000, maxEntityBodySize: 50 }});
Improve listener/client return type to union with error
Listener and client initialization may return an error now. When the listener is used in a listener declaration, module initialization will fail if the listener initialization returns an error.
New syntax:
http:Listener|http:ListenerError ep = new (9090); http:Client|http:ClientError myClient = new ("http://localhost:9100", {httpVersion: "2.0"});
Improve the getHeader()
and getHeaders()
return types to union with error
New syntax:
string|error value = request.getHeader("Content-Type"); string[]|error values = request.getHeaders("Accept");
Remove status code related http:Caller
methods
The http:Caller
remote methods such as ok()
, created()
, accepted()
, noContent()
, badRequest()
, notFound()
, and internalServerError()
were removed along with the response record introduction
WebSocket module improvements
- The Websocket module has been moved out of the HTTP module. Therefore, the import should be changed from
ballerina/http
toballerina/websocket
. - Introduced a new listener as follows for the WebSocket module.
listener websocket:Listener wsListener = new(9090);
- This module now has the two types of services below that are mandatory to work with WebSockets.
websocket:UpgradeService
- This handles the HTTP to WebSocket upgrade. This service has a single get resource, which returns awebsocket:Service
or an error. Optionally, this takes in thehttp:Request
parameter. To accept the WebSocket upgrade, this resource should return awebsocket:Service
. Or else, to cancel the WebSocket upgrade, it must return awebsocket:UpgradeError
.websocket:Service
- This handles the events after the WebSocket upgrade. This service has a predefined set of remote methods likeonTextMessage
,onBinaryMessage
,onError
,onPing
,onPong
,onOpen
,onClose
. Once the connection is successfully updated to a WebSocket connection, upon receiving WebSocket frames/messages, those will get dispatched to these remote methods.
New syntax:
import ballerina/http; import ballerina/websocket; service / basic on new websocket:Listener(9000) { resource function get .(http:Request req) returns websocket:Service|websocket:UpgradeError { return new WsService(); } } service class WsService { *websocket:Service; remote function onOpen(websocket:Caller caller) { } remote function onTextMessage(websocket:Caller caller, string text) { } remote function onBinaryMessage(websocket:Caller caller, byte[] b) { } }
The onTextMessage
and onBinaryMessage
will take in the complete WebSocket message. Unlike earlier versions, onTextMessage
doesn't support data binding. WebSocket messages dispatched to this remote method will only be in the string
format.
The websocket:Caller
has writeTextMessage
, writeBinaryMessage
, ping
, pong
, and, close
as remote methods. Unlike earlier versions, writeTextMessage
doesn't support data binding. Complete messages only in the string format will be accepted by this.
New syntax:
ler->writeTextMessage(text); ler->writeBinaryMessage(byteArr);
-
Introduced a WebSocket Async client The WebSocket module now has a
websocket:AsyncClient
. This client can take in awebsocket:Service
as a callback service to receive WebSocket messages at the client initialization. This service has a predefined set of remote methods likeonTextMessage
,onBinaryMessage
,onError
,onPing
,onPong
,onOpen
, andonClose
.New syntax
import ballerina/websocket; public function main() returns websocket:Error? { websocket:AsyncClient wsClientEp = check new ("ws://echo.websocket.org", new ClientService()); var err = wsClientEp->writeTextMessage("Hello World!"); } service class ClientService { *websocket:Service; remote function onTextMessage(websocket:Caller conn, string text) { } }
The
websocket:AsyncClient
has thewriteTextMessage
,writeBinaryMessage
,ping
,pong
, andclose
remote methods.New syntax:
asyncClient>writeTextMessage(text); asyncClient>writeBinaryMessage(byteArr);
-
Improved the listener/client return type to union with error Listener and client initialization may return an error now. When the listener is used in a listener declaration, module initialization will fail if the listener initialization returns an error.
New syntax:
websocket:Listener|websocket:Error ep = new (9090); websocket:AsyncClient|websocket:Error wsClient = new ("ws://echo.websocket.org");
gRPC module improvements
Service changes
- Enable returning specific data types directly from the remote methods (even record types and streams).
service "Chat" on ep { remote function chat(stream<string, error?> clientStream) returns stream<string, error?> { } }
- Add support to send/receive custom headers in the request/response path.
Client changes
- Clients have the capability to receive a stream object in the server streaming scenario.
stream<string, grpc:Error?> result = check endpoint->chat("WSO2");
- In the client and bidirectional streaming use cases, it returns a streaming client that has the capability to read and write data.
grpc:StreamingClient streamingClient = check endpoint->chat(); // Send messages check streamingClient->send(msg); // Receives messages var result = streamingClient->receive();
- Added the support to send/receive custom headers in the request/response path.
Protobuf tool
- Generate a custom caller object from the Protobuf tool
- Generate a custom streaming client from the Protobuf tool
- Update the Protobuf tool to generate specific types using langlib data types
Security improvements
Ballerina listener authentication and authorization, and client authentication were completely redesigned. The new design is compatible with most of the standard libraries like HTTP, gRPC, WebSocket, etc.,
HTTP listener authentication and authorization
A Ballerina HTTP listener can be configured to authenticate and authorize the inbound requests. Ballerina has built-in support for the following listener authentication mechanisms.
- Basic authentication
- LDAP user store
- JWT authentication
- OAuth2 authentication
For more information, see HTTP Listener Authentication and Authorization.
HTTP client authentication
The Ballerina HTTP client can be configured to send authentication information to the endpoint being invoked. Ballerina has built-in support for the following client authentication mechanisms.
- Basic authentication
- JWT authentication
- Self-signed JWT
- Bearer token
- OAuth2 authentication
- Client credentials grant type
- Password grant type
- Direct token type
GraphQL module improvements
Introspection support
Ballerina GraphQL services now support introspection queries on the schema.
Improved resource methods
GraphQL resources may now return error values.
Common changes in messaging modules
- The
resource
methods are changed toremote
methods in the new listener APIs. - The
service
name is given as a string with the new Ballerina language changes.
TCP module improvements
The Socket module is replaced by the TCP module. Therefore, the import statement needs to be changed from ballerina/socket
to ballerina/tcp
.
New APIs for the client and listener are introduced in the TCP module.
Client changes
tcp:Client
initialization may now returntcp:Error
if an error occurs while initializing the client.- The name of the
write
method changed towriteBytes
. You don’t have to explicitly write a while loop to ensure the data is written completely as before. Instead, thewriteBytes
method ensures to write the data completely. - The name of the
read
method changed toreadBytes
. This method now returnsreadonly & byte[]
instead of[byte[], int]
.
New syntax:
import ballerina/tcp; public function main() returns tcp:Error? { tcp:Client socketClient = check new ("localhost", 3000); check socketClient->writeBytes(“Hello Ballerina”.toBytes()); readonly & byte[] receivedData = check socketClient->readBytes(); check socketClient->close(); }
Service and listener changes
New syntax:
listener tcp:Listener socketListener = new (9090);
The service type with resource methods is removed from the module. The new implementation has the following two types of services.
tcp:Service
which handles a TCP connection. This service has a predefinedonConnect
remote method that returnstcp:ConnectionService
ortcp:Error?
.tcp: ConnectionService
which handles the traffic between the client and server. This can have the following optional remote methods.remote function onBytes(readonly & byte[] data) returns Error? { }
remote function onClose() returns Error? { }
remote function onError(readonly & Error err) returns Error? { }
The read
method is removed from tcp:Caller
. Also, the write
method of Caller
is renamed to writeBytes
, which is similar to the Client’s writeBytes
method.
New syntax:
import ballerina/tcp; service on new tcp:Listener(3000) { remote function onConnect(tcp:Caller caller) returns tcp:ConnectionService { return new TCPService(caller); } } service class TCPService { tcp:Caller caller; public function init(tcp:Caller c) { self.caller = c; } remote function onBytes(readonly & byte[] data) returns byte[]|tcp:Error? { return data; } remote function onClose() returns tcp:Error? { } remote function onError(readonly & tcp:Error err) returns tcp:Error? { } }
UDP module improvements
The UDP module has been moved out of the Socket module. Therefore, it is required to change the import from ballerina/socket
to ballerina/udp
.
Client changes
-
udp:Client
initialization may now returnudp:Error
if an error occurred while initializing the client. -
The name of the
sendTo
method changed tosendDatagram
. This takes audp:Datagram
as a parameter. You don’t need to explicitly write a while loop to ensure the data is written completely. ThewriteBytes
method ensures to write the data completely. -
The name of the
receiveFrom
method changed toreceiveDatagram
. This now returnsreadonly & udp:Datagram
instead of[byte[], int, socket:Address]
.New syntax:
import ballerina/udp; public function main() returns udp:Error? { udp:Client socketClient = check new; udp:Datagram datagram = { remoteHost: "localhost", remotePort: 48829, data: "Hello Ballerina".toBytes() }; check socketClient->sendDatagram(datagram); readonly & udp:Datagram result = check socketClient->receiveDatagram(); check socketClient->close(); }
Introduced
ConnectClient
andListener
to the new UDP module as follows.ConnectClient:
import ballerina/udp; public function main() returns udp:Error? { udp:ConnectClient socketClient = check new ("localhost", 48829); check socketClient->writeBytes("Hello Ballerina".toBytes()); readonly & byte[] result = check socketClient->readBytes(); check socketClient->close(); }
Listener:
import ballerina/udp; service on new udp:Listener(48829) { remote function onBytes(readonly & byte[] data, udp:Caller caller) returns (readonly & byte[])|udp:Error? { return data; } remote function onError(readonly & udp:Error err) { } }
Kafka module improvements
Client changes
-
The
kafka:Consumer
is separated intokafka:Listener
(asynchronous) andkafka:Consumer
(synchronous). -
The return type of the
init
methods of thekafka:Producer
andkafka:Consumer
is changed toError?
. -
The
subscribeToPattern()
method of thekafka:Consumer
is changed tosubscribeWithPattern()
. -
A new record type named
ProducerRecord
is introduced for sending messages.public type ProducerRecord record {| string topic; byte[] key?; byte[] value; int timestamp?; int partition?; |};
-
The
send()
method of thekafka:Producer
is changed tosendProducerRecord(ProducerRecord producerRecord)
. An example of sending a message with the new API is given below.string message = "Hello World, Ballerina"; kafkaProducer->sendProducerRecord({topic: "test-kafka-topic", value: message.toBytes()});
Service and listener changes
-
The return type of the
init
method ofkafka:Listener
is changed toError?
. -
Has a single type of service that supports the remote method below:
onConsumerRecord(kafka:Caller caller, kafka:ConsumerRecord[] record) {}
-
The
kafka:Caller
is introduced to remote functions to commit offsets of the consumed records. -
The new syntax with the service changes is given below.
listener kafka:Listener kafkaListener = new (consumerConfigs); service kafka:Service on kafkaListener { remote function onConsumerRecord(kafka:Caller caller, kafka:ConsumerRecord[] records) { // Process consumed records } }
NATS module improvements
-
The
ballerinax/nats
module is split into two packages asballerinax/nats
(NATS client) andballerinax/stan
(NATS Streaming client). -
The
nats:Connection
object is removed entirely. -
The
nats:Producer
client is renamed tonats:Client
. -
The return type of the
nats:Client
client is changed toError?
. -
The
nats:Message
object is changed into a record type.public type Message record {| byte[] content; string subject; string replyTo?; |};
-
The
publish()
method of thenats:Producer
is changed topublishMessage(Message message)
of thenats:Client
. An example of sending a message with the new API is given below.string message = "Hello from Ballerina"; nats:Client natsClient = check new; check natsClient->publishMessage({ content: message.toBytes(), subject: "demo.bbe.subject" });
Service and listener changes
-
The return type of the
init
method ofnats:Listener
is changed toError?
. -
Has a single type of service that supports the two types of remote functions below:
onMessage(nats:Message message) {}
onRequest(nats:Message message) returns anydata {}
-
A new
onRequest
remote method is introduced to directly reply to a message by returning a value if thereplyTo
subject is present. -
If the subject name is not given in the
@nats:ServiceConfig
, the name of the service is considered as the subject name. -
The new syntax with the service changes is given below.
import ballerinax/nats; listener nats:Listener subscription = new; @nats:ServiceConfig {subject: "demo.bbe.*"} service nats:Service on subscription { remote function onMessage(nats:Message message) { } }
NATS streaming module improvements
A new package named ballerinax/stan
is introduced to handle the NATS Streaming Server related functionality.
Client changes
-
nats:Connection
is removed entirely from the NATS Streaming client as well. -
stan:Client
is introduced to handle the client-side functionality. -
An example of sending messages using the new
ballerinax/stan
package to a NATS Streaming server is given below.import ballerinax/stan; public function main() returns error? { string message = "Hello from Ballerina"; stan:Client stanClient = check new; string result = check stanClient->publishMessage({ content: message.toBytes(), subject: "demo" }); }
Service and listener changes
-
The return type of the
init
method ofstan:Listener
isError?
. -
Has a single type of service that supports the
onMessage
remote method below:onMessage(nats:Message message) {}
-
If the subject name is not given in the
@stan:ServiceConfig
, the name of the service is considered as the subject name. -
The new syntax with the service changes is given below.
import ballerinax/stan; listener stan:Listener lis = new; @stan:ServiceConfig {subject: "demo"} service stan:Service on lis { remote function onMessage(stan:Message message) { } }
RabbitMQ module improvements
Client changes
-
rabbitmq:Connection
is removed entirely. -
rabbitmq:Channel
is renamed torabbitmq:Client
, which will handle the client-side functionality. Theinit
method ofrabbitmq:Client
returnsError?
. -
The
rabbitmq:Message
object is changed into a record type.public type Message record {| byte[] content; string routingKey; string exchange = ""; int deliveryTag?; BasicProperties properties?; |};
-
The
queueDeclare()
method ofrabbtimq:Channel
is split intoqueueDeclare()
andqueueAutoGenerate()
ofrabbtimq:Client
. -
The
basicPublish()
method ofrabbitmq:Channel
is changed topublishMessage(Message message)
of therabbitmq:Client
. An example of sending a message with the new API is given below.import ballerinax/rabbitmq; public function main() returns error? { rabbitmq:Client newClient = check new; check newClient->queueDeclare("MyQueue"); string message = "Hello from Ballerina"; check newClient->publishMessage({ content: message.toBytes(), routingKey: "MyQueue" }); }
Service and listener changes
-
The return type of the
init
method ofrabbitmq:Listener
is changed toError?
. -
Has a single type of service that supports the three types of remote functions below:
onMessage(rabbitmq:Message message) {}
onMessage(rabbitmq:Message message, rabbitmq:Caller caller) {}
onRequest(rabbitmq:Message message) returns anydata {}
-
A new
onRequest
method is introduced to directly reply to a message by returning a value if thereplyTo
subject is present. -
If the subject name is not given in the
@rabbitmq:ServiceConfig
, the name of the service is considered as the subject name. -
The new syntax with the service changes is given below.
import ballerinax/rabbitmq; listener rabbitmq:Listener channelListener = new; @rabbitmq:ServiceConfig {queueName: "MyQueue"} service rabbitmq:Service on channelListener { remote function onMessage(rabbitmq:Message message) { } }
Time module improvements
The improvements below have been introduced to the ballerina/time
module.
- Added support for commonly-used date-time formatters in the
time:format()
andtime:parse()
APIs. - The hours, minutes, seconds, milliseconds, and zone ID parameters of the
time:createTime()
method have been made defaultable. - Introduced a new
time:Duration
record type to represent a chunk of time. - Modified the
time:addDuration()
andtime:subtractDuration()
methods to accept thetime:Duration
records to be added/subtracted. - Introduced a new
time:getDifference()
method to calculate the difference between twotime:Time
records. - Introduced a new
time:getTimezones()
method to retrieve the timezone IDs supported by the underlying native code. - Introduced an enum to represent the days of the week and modified the
time:getWeekday()
method to return this enum.
Runtime module improvements
The methods below have been removed from the runtime
module since these methods have moved to the lang:runtime
lang library.
sleep
getCallStack
Email module improvements
Common changes for client and server configurations
-
email:Email
is changed toemail:Message
. -
Attachment support is improved to support file attachments directly with its content type. The new
email:Attachment
record is as follows.
public type Attachment record {| string filePath; string contentType; |};
-
The
email:Message
record is modified to accept either astring
or astring[]
for theto
,cc
,bcc
, andreplyTo
fields to add flexibility. An optionalhtmlBody
field is added to support the HTML body. The new record is as follows.Note how the
attachments
field is modified.public type Message record {| string|string[] to; string subject; string 'from; string body; string htmlBody?; string|string[] cc?; string|string[] bcc?; string|string[] replyTo?; string contentType?; map<string> headers?; string sender?; Attachment|(mime:Entity|Attachment)[] attachments?; |}
-
The
enableSsl
boolean field is replaced with thesecurity
field to enable different types of transport-layer security. This new parameter is an enumeration with theSTART_TLS_AUTO|START_TLS_ALWAYS|START_TLS_NEVER|SSL
options. The default/undefined value isSSL
. -
Self-signed certificate support is added while default SSL/TLS support is restricted to self-signed certificates with relevant configurations and CA-certified certificates. Hostname verification is made mandatory for SSL/TLS support. Anyway, hostname verification can be disabled with the configuration by passing the value of the
mail.smtp.ssl.checkserveridentity
property as”false”
.
Client changes
-
A new
sendEmail
method is added to theemail:SmtpClient
API to send emails directly without creating theemail:Email
record supporting extra fields as named optional parameters. An example of sending an email with the new API is given below.Error? response = smtpClient->sendEmail(toAddresses, subject, fromAddress, body, cc = ccAddresses, bcc = bccAddresses, htmlBody = htmlBody, contentType = contentType, headers = {header1_name: "header1_value"}, sender = sender, replyTo = replyToAddresses, attachments = bodyParts);
-
The
read
method ofemail:ImapClient
,email:PopClient
, andemail:Listener
(i.e.,new email:PopListener
andemail:ImapListener
) are changed toreceiveEmailMessage
. -
All client initializations return an
email:Error
when an error occurs during the initialization.
Service and listener related changes
-
All listener initializations return an
email:Error
when an error occurs during the initialization. -
The
email:Listener
is split into theemail:PopListener
andemail:ImapListener
. Therefore, theprotocol
field is removed from the new protocol-specific listeners. Theemail:PopConfig
oremail:ImapConfig
that were used as fields for theemail:Listener
are not required for the new API implementation. Protocol configuration related fields are made parts of the new listeners. -
The
resource
methods are changed toremote
methods in the new listener APIs. -
The
service
name is given as a string with the new Ballerina language changes. -
The
onMessage
method of theemail:Listener
(i.e.,new email:PopListener
andemail:ImapListener
) is changed toonEmailMessage
. -
The
pollingInterval
field of theemail:Listener
is changed topollingIntervalInMillis
in the new listener APIs. That makes it consistent across other Ballerina modules, in which time durations are configured in milliseconds. -
A sample POP3 listener is given below.
New syntax:
listener email:PopListener emailListener = new ({ host: "pop.email.com", username: "reader@email.com", password: "pass456", pollingIntervalInMillis: 2000, port: 995 }); service "emailObserver" on emailListener { remote function onEmailMessage(email:Message emailMessage) { } remote function onError(email:Error emailError) { } }
WebSub module improvements
Hub-related changes
- Default implementation for the
websub:Hub
has been removed from the module. - API specification for the WebSub Hub is moved to the
websubhub
module.
Publisher-related changes
- The implementation related to the
websub:PublisherClient
is moved to thewebsubhub
module.
Subscriber-related changes
-
The two new configurations below are introduced to the
@websub:SubscriberServiceConfiguration
for hub/topic discovery.accept
- The expected media typeacceptLanguage
- The expected language type
-
API specification for the
@websub:SubscriberService
is updated with the changes below.- The
onIntentVerification
andonNotification
methods are removed. - The
onSubscriptionVerification
,onEventNotification
, andonSubscriptionValidationDenied
methods are introduced.
- The
-
The updated
websub:SubscriberService
sample implementation is as follows.listener websub:Listener testListener = new (9090); @websub:SubscriberServiceConfig { target: ["http://localhost:9191/websub/hub", "http://websubpubtopic.com"], leaseSeconds: 36000, secret: "Kslk30SNF2AChs2" } service /subscriber on testListener { remote function onSubscriptionValidationDenied(SubscriptionDeniedError msg) returns Acknowledgement { // execute subscription validation denied action } remote function onSubscriptionVerification(SubscriptionVerification msg) returns SubscriptionVerificationSuccess| SubscriptionVerificationError { // execute subscription verification action } remote function onEventNotification(ContentDistributionMessage event) { // execute event notification received action } }
Introduced new modules
Random
The ballerina/random
module provides functions related to random number generation.
RegEx
The ballerina/regex
module provides RegEx utilities such as checking whether a string matches a given RegEx, replacing substrings, and splitting strings based on a RegEx.
WebSubHub
- This module contains the API specifications and implementations related to the WebSub Hub, WebSub Hub Client, and WebSub Publisher.
- This is an inter-dependent module for the
websub
module.
Hub Implementation
-
The default
websub:Hub
implementation has been removed and language-specific API abstraction is defined in thewebsubhub:Service
. -
Updated WebSub Hub sample implementation to comply with the new API specification is as follows.
listener websubhub:Listener hubListener = new (9001); service /websubhub on hubListener { remote function onRegisterTopic(websubhub:TopicRegistration message) returns websubhub:TopicRegistrationSuccess|websubhub:TopicRegistrationError { // implement action to execute on topic-registration } remote function onDeregisterTopic(websubhub:TopicDeregistration message) returns websubhub:TopicDeregistrationSuccess|websubhub:TopicDeregistrationError { // implement action to execute on topic-deregistration } remote function onUpdateMessage(websubhub:UpdateMessage msg) returns websubhub:Acknowledgement|websubhub:UpdateMessageError { // implement action to execute on content-update for topic } remote function onSubscription(websubhub:Subscription msg) returns websubhub:SubscriptionAccepted|websubhub:SubscriptionPermanentRedirect| websubhub:SubscriptionTemporaryRedirect|websubhub:BadSubscriptionError| websubhub:InternalSubscriptionError { // implement action to execute on new subscription } remote function onSubscriptionValidation(websubhub:Subscription msg) returns websubhub:SubscriptionDeniedError? { // implement action to execute on subscription validation } remote function onSubscriptionIntentVerified(websubhub:VerifiedSubscription msg) { // implement action to execute on subscription intent verification } remote function onUnsubscription(websubhub:Unsubscription msg) returns websubhub:UnsubscriptionAccepted|websubhub:BadUnsubscriptionError| websubhub:InternalUnsubscriptionError { // implement action to execute on unsubscription } remote function onUnsubscriptionValidation(websubhub:Unsubscription msg) returns websubhub:UnsubscriptionDeniedError? { // implement action to execute on unsubscription validation } remote function onUnsubscriptionIntentVerified(websubhub:VerifiedUnsubscription msg) { // implement action to execute on unsubscription intent verification } }
Hub Client implementation
-
websubhub:Client
is introduced to distribute the updated content to subscribers. -
The example below is a sample use-case of the WebSub Hub Client.
service /websubhub on hubListener { remote function onSubscriptionIntentVerified(websubhub:VerifiedSubscription msg) { // Client configuration (e.g., retry config) can be passed if required. websubhub:HubClient hubclient = check new (msg); var responseFuture = start notifySubscriber(hubclient); } function notifySubscriber(websubhub:HubClient hubclient) returns error? { while (true) { // Fetch the messages to be delivered. ContentDistributionSuccess | SubscriptionDeletedError | error publishResponse = check hubclient->notifyContentDistribution({content: "This is sample content delivery"}); } } }
Publisher implementation
websub:PublisherClient
is moved to ballerina/websubhub
and can now be used as websubhub:PublisherClient
.
Removed modules
Config
The configuration use cases are now covered under the configurable
language feature.
Math
The APIs related to random number generation were moved to the new random
module. The rest of the APIs have replacements in the lang.float
and lang.int
packages.
Stringutils
The regex-related APIs that were supported by this module have been moved to the new regex
module. The rest of the APIs have replacements in the langlib packages.
Rename system module to OS
The previous ballerina/system
module is now renamed to ballerina/os
. All the Operating System independent functionalities are included in this module.
Observability
-
A new extension model, which separates each extension into a separate module is introduced.
-
Observability can be included in the final JAR by adding the following configuration in the
Ballerina.toml
file.[build-options] observabilityIncluded=true
-
The observability extension can be packaged by adding an import to the module in the code as shown in the example below.
import ballerinax/prometheus as _;
-
-
Prometheus
andJaeger
extensions are introduced back.-
The
Prometheus
extension can be enabled by adding the following configuration in theConfig.toml
file.[ballerina.observe] metricsEnabled=true metricsReporter="prometheus" [ballerinax.prometheus] host="127.0.0.1" # Optional Configuration. Default value is localhost port=9797 # Optional Configuration. Default value is 9797
-
The
Jaeger
extension can be enabled by adding the following config.[ballerina.observe] tracingEnabled=true tracingProvider="jaeger" [ballerinax.jaeger] agentHostname="127.0.0.1" # Optional Configuration. Default value is localhost agentPort=6831 # Optional Configuration. Default value is 6831
-
By default, the
Jaeger
extension now publishes traces to the Jaeger Agent using thejaeger.thrift
over the compact Thrift protocol.
-
Code to Cloud
- The Kubernetes artifacts can be generated using the
--cloud=k8s
build option. Theimport ballerina/cloud as _
import is no longer required. - VS code plugin support for the
Kubernetes.toml
- Code Completion based on the c2c specification.
- Code Actions add/modify the probes and environments based on the source code.
Breaking changes
- Resource method declarations are no longer allowed in object-type descriptors.
- Resource methods are not considered to be part of the type.
- Non-
isolated
service variables defined outside anisolated
function can be accessed within the function only if the variable is afinal
variable and the type is a subtype ofreadonly
. - The
@icon
annotation has been replaced with the@display
annotation. - The value type of XML iteration, which was previously
xml|string
is nowxml
. Moreover, the value type ofxml<T>
iteration is nowT
.
Taint analyzer update
With this release, the taint analyzer does not produce taint errors unless explicitly enabled. However, the taint analyzer still performs the taint flow analysis without producing errors if error logging is not enabled.
This is enabled via the build option below in the Ballerina.toml
file
[build-options] taintCheck = true
or else, by using the --taint-check
option in the Ballerina CLI tools as follows.
bal run --taint-check [file.bal | project] bal build --taint-check [file.bal | project]