eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

We can independently create and run a simple Java class with just a Java installation. However, including third-party dependencies usually requires a build tool like Maven or Gradle, which can be cumbersome for small and straightforward Java applications. Packaging a Java app as an executable also requires adding plugins to these build tools or using separate tools.

Fortunately, we can simplify Java app development for smaller projects using a practical Scala tool called Scala-CLI. In this tutorial, we’ll explore Scala-CLI’s features and how to use it for tasks like compiling, building, packaging, and using specific JDKs.

2. What Is Scala-CLI?

Scala-CLI is a command-line tool primarily designed for building Scala applications. It simplifies compiling, running, and packaging Scala applications, eliminating the need for a comprehensive build system.

Interestingly, Scala-CLI can also build pure Java applications, leveraging its full capabilities to streamline development.

3. Set-Up

Scala-CLI can be installed by following the instructions provided on the official website. We can verify if the installation is successful by using the following command:

scala-cli --version

If the installation is successful, it prints the scala-cli version to the console.

Furthermore, we can install the Metals extension in VS Code Editor to work inside an IDE. Scala-CLI doesn’t need a pre-installed JDK on the machine, as it can manage the JDK itself.

However, sometimes, there might be a conflict with the other Java plugins. If there is an issue with error reporting in VS Code, we might need to disable the other Java extension temporarily.

We’ll also create a base directory named scala-cli for this tutorial, where we keep all the files related to this tutorial.

4. Hello World Program

As is the norm, let’s start with a simple Hello World program. First, we can create a new hello-world directory under the base directory. Next, let’s create a file named HelloWorld.java within this directory with the following code:

package com.baeldung;
public class HelloWorld {
    public static void main(String args[]) {
        System.out.println("Hello, World!");
    }
}

We can run this simple Java class using the command:

scala-cli HelloWorld.java

On the first run, it downloads the necessary libraries for it to run. If no JDK is installed, Scala-CLI automatically downloads the Open JDK and uses it for compilation. If there is already one available, then it uses that particular JDK. While writing this article, Scala-CLI uses the JDK 17 as the default version. However, it might upgrade to newer versions in the future. After that, it runs this class and prints the given text to the console:

Hello World Output

If we open this directory in VS Code, we might see compilation errors and need proper navigation ability. The VS Code might be able to apply navigation and code completion in this case; however, when we use third-party dependencies, it won’t resolve them. To support it, we can create the necessary metadata for the Metals plugins by using the command inside the hello-world directory:

scala-cli setup-ide .

This generates the necessary metadata required by the Metals plugin for advanced features.

The Metals plugin also provides a tooltip to run the main class directly from the VS Code IDE:

VS Code Metals Run

We can click on the run action, and it executes the program.

5. Directives

In the previous section, we ran a simple program using Scala-CLI. However, the same can be done with the java command, and doesn’t need another tool. Now, let’s look at some of Scala-CLI’s most useful features.

Directives are metadata settings that have special meanings in Scala-CLI. The directives start with the special syntax //>. They must be placed before any Java code, even before the package statement. In this section, let’s explore some of the useful directives in Scala-CLI.

5.1. Specifying Java Version

In the previous sample code, we didn’t specify any Java version, and it uses either the default JDK or the already installed JDK for the execution. However, we can configure a specific version of JDK we want the code to use. For that, we use the jvm directive.

Let’s write a sample code that uses JDK 21. We can name the file as Directives.java and place it under scala-cli/jdk-config path:

//> using jvm 21
package com.baeldung;
record Greet(String name){};
public class Jdk21Sample {
    public static void main(String args[]) {
        var greet = new Greet("Baeldung");
        var greeting = "Hello, " + greet.name();
        System.out.println(greeting);
    }
}

Notice the directive jvm being used with the required version of JDK. This means the Scala-CLI uses JDK 21 to execute the entire file.

By default, it uses Adoptium Open JDK of the specified version. We can also select another flavor of JDK explicitly in the directive. For example, to use Zulu JDK, we can use the directive:

//> using jvm zulu:21

When we run this directive, Scala-CLI downloads the Zulu JDK and executes the program using it. Without any manual setup, we can easily switch between different JDKs and execute the programs. Under the hood, Scala-CLI uses the tool Coursier to manage the dependencies and the JDK versions.

5.2. Passing Javac Options and Java Properties

We can use directives to pass Java options to the compiler. Let’s look at an example:

//> using jvm 21
//> using javaOpt -Xmx2g, -DappName=baeldungApp, --enable-preview
//> using javaProp language=english, country=usa
//> using javacOpt --release 21 --enable-preview
public class JavaArgs {
    public static void main(String[] args) {
        String appName = System.getProperty("appName");
        String language = System.getProperty("language");
        String country = System.getProperty("country");
        String combinedStr = STR."appName = \{ appName } , language = \{ language } and country = \{ country }";
        System.out.println(combinedStr);
    }
}

The code above passes three different types of options. We can use the directive javaOpt to pass the JVM arguments such as -Xmx or system properties. Similarly, we can use javacOpt to pass options to the javac compiler used during the compilation. Furthermore, we can also pass Java properties to the application by using the directive javaProp.

These directives enable configuring and controlling arguments directly within the main Java class.

5.3. Managing External Dependencies

We can manage external dependencies using the directive dep. To demonstrate this, let’s add a simple library. We can create a new file named DependencyApp.java and paste the following content:

//> using dep com.google.code.gson:gson:2.8.9
import com.google.gson.JsonParser;
import com.google.gson.JsonElement;
public class DependencyApp {
    public static void main(String args[]) {
        String jsonString = "{\"country\": \"Germany\", \"language\": \"German\", \"currency\": \"Euro\"}";
        var countryJson = JsonParser.parseString(jsonString);
        var country = countryJson.getAsJsonObject().get("country").getAsString();
        System.out.println("Selected country: " + country);
    }
}

In the code above, we added the dependency for Google Gson using the directive dep. Scala-CLI uses the gradle style syntax for dependency definition.

When we execute the t code, we get the output as:

Compiled project (Java)
[hint] ./DependencyApp.java:1:15
[hint] "gson is outdated, update to 2.11.0"
[hint]      gson 2.8.9 -> com.google.code.gson:gson:2.11.0
[hint] //> using dep com.google.code.gson:gson:2.8.9
[hint]               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Selected country: Germany

We can observe that Scala-CLI can detect the library version and suggest updates if a newer version is available. This feature is convenient for maintaining up-to-date dependencies without manually searching the Maven Central repository.

6. Packaging the Java Application as an Executable

One of Scala-CLI’s most valuable features is its ability to create executable applications directly from code without requiring additional plugins. Let’s explore creating an executable application using the previously created file, DependencyApp.java.

We can use the following command to create the executable:

scala-cli --power package DependencyApp.java -o myApp --assembly

The package command creates a package. The –power flag indicates that this is a power-user command. We can specify the executable app name using the argument -o. If we include the –assembly flag, Scala-CLI will create an executable JAR; otherwise, it creates a library JAR.

Scala-CLI creates an executable JAR by default when we use the assembly flag and wrap it in a standalone script. To run the created package, use the command:

./myApp

Instead of creating a wrapper executable, we can generate a simple JAR by passing an additional flag.

scala-cli --power package DependencyApp.java -o myApp.jar --assembly --preamble=false

Now, we can execute it as follows:

java -jar myApp.jar

Similarly, Scala-CLI allows us to create Docker images, GraalVM native images, and platform-specific formats such as deb, msi, etc.

7. Conclusion

In this article, we explored several key features of Scala-CLI, a tool similar to JBang. Scala-CLI, while strongly emphasizing Scala, also provides robust support for Java applications. We demonstrated how Scala-CLI streamlines development by simplifying various aspects of application building, offering easy customization, support for different packaging formats, and more.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LS – NPI (cat=Java)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)