Enterprise Java

Spring Boot Pkl Example

Pkl is a configuration-as-code language developed by Apple, blending the simplicity of static formats like JSON with the expressiveness of programming languages. It aims to enhance configuration management by introducing features such as classes, functions, and type annotations, ensuring scalability and safety in complex configurations. Let us understand Spring Boot Pkl integration step by step, covering its use cases, benefits, implementation, and real-world API examples.

1. Introducing Pkl: A Programming Language for Configuration

Pkl (pronounced “Pickle”) is an open-source programming language specifically designed to handle configuration tasks. It aims to blend the simplicity of static configuration formats like JSON and YAML with the expressiveness of general-purpose programming languages. This combination allows for more scalable, safe, and maintainable configurations.

1.1 Why Pkl?

Traditional configuration formats often face challenges as projects grow in complexity:

  • Repetition and Maintainability: Static formats lack mechanisms to avoid code repetition, making configurations harder to maintain.
  • Validation: These formats typically don’t offer built-in validation, increasing the risk of errors during deployment.
  • Complex Enhancements: Adding features like templating or validation to static formats can lead to convoluted solutions that are hard to manage.

Pkl addresses these issues by offering:

  • Declarative Syntax: Easy-to-read syntax similar to static formats.
  • Programming Constructs: Features like classes, functions, conditionals, and loops to build abstractions and reduce repetition.
  • Rich Validation: A robust type and validation system to catch errors before deployment.

1.2 Benefits

Following are the key features of Pkl, a configuration language, highlighting its ease of use, versatility, and developer-friendly features:

  • Programmable: Combines declarative configuration with programming capabilities.
  • Scalable: Suitable for both simple and complex configuration tasks.
  • Safe: Ensures configurations are validated, reducing runtime errors.
  • Versatile Output: Generates configurations in formats like JSON, YAML, Property Lists, and more.
  • Embeddable: Can be integrated into applications, with code generation support for languages such as Java, Kotlin, Swift, and Go.
  • IDE Integration: Offers plugins and extensions for popular IDEs like IntelliJ, Visual Studio Code, and Neovim, enhancing the development experience.

2. Spring Boot Application with Pkl

2.1 Dependencies

Add the following dependencies to your build.gradle file:

01
02
03
04
05
06
07
08
09
10
11
12
13
dependencies {
    // Spring Boot Starter for Web
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // Spring Boot Configuration Processor
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    // Pkl Spring Boot Starter (If available in the repository)
    implementation 'org.pkl-lang:pkl-spring-boot-starter:1.0.0' // Replace with the latest version
    // Lombok (Optional for reducing boilerplate code)
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    // Spring Boot Test Dependencies
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

As we are using Lombok in this project, make sure to enable Annotation Processing in your IntelliJ IDE.

2.2 Define the Pkl Configuration Schema

First, create a Pkl schema to outline the application’s configuration structure. The schema will serve as a blueprint for generating corresponding Java classes. Let’s define a schema in src/main/resources/appConfig.pkl.

01
02
03
04
05
06
07
08
09
10
11
12
module samples.boot.AppConfig
 
server: Server
 
class Server {
    endpoints: Listing<Endpoint>
}
 
class Endpoint {
    name: String
    port: UInt16
}

The code defines a module named “samples.boot.AppConfig” containing a class “Server” and a class “Endpoint”. The “Server” class has an attribute “endpoints”, which is a list of “Endpoint” objects. The “Endpoint” class has two attributes: “name”, which is a string, and “port”, which is an unsigned 16-bit integer (UInt16). This structure defines a configuration setup for a server with a list of endpoints, each having a name and a port number.

2.3 Create the Application Configuration File

Next, define the actual configuration values in a Pkl file, such as src/main/resources/application.pkl.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
amends "modulepath:/appConfig.pkl"
 
server {
    endpoints {
        new {
            name = "endpoint1"
            port = 1234
        }
        new {
            name = "endpoint2"
            port = 5678
        }
    }
}

The code defines a configuration in Pkl format, referring to a module located at “modulepath:/appConfig.pkl”. It specifies a “server” block that contains an “endpoints” block, within which two new endpoints are defined. The first endpoint is named “endpoint1” and is assigned port 1234, while the second endpoint is named “endpoint2” with port 5678. This configuration sets up two endpoints for the server with specified names and port numbers.

2.4 Configure the Build Tool

Use the Pkl Gradle plugin to generate Java classes from the Pkl schema. In your build.gralde file, apply the plugin and configure the code generation.

01
02
03
04
05
06
07
08
09
10
11
12
plugins {
    id "org.pkl-lang" version "1.0.0" // Replace with the latest version version
}
 
pkl {
    javaCodeGenerators {
        configClasses {
            generateGetters.set(true)
            generateSpringBootConfig.set(true)
        }
    }
}

This setup guarantees that the Pkl schema is processed to automatically generate Java configuration classes with getters and Spring Boot configuration support. To generate these Java classes, simply execute the following Gradle task:

1
./gradlew build

By performing this step, we can eliminate the need to manually create POJOs to map to the Pkl configuration.

2.4.1 Generated POJO Class

After running the gradle command to process the Pkl schema, we will get the following Java classes.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.List;
 
public class AppConfig {
    private Server server;
 
    public Server getServer() {
        return server;
    }
    public void setServer(Server server) {
        this.server = server;
    }
 
    public static class Server {
        private List<Endpoint> endpoints;
 
        public List<Endpoint> getEndpoints() {
            return endpoints;
        }
        public void setEndpoints(List<Endpoint> endpoints) {
            this.endpoints = endpoints;
        }
    }
 
    public static class Endpoint {
        private String name;
        private int port;
 
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
 
        public int getPort() {
            return port;
        }
        public void setPort(int port) {
            this.port = port;
        }
    }
}

Make sure to annotate this POJO class with @ConfigurationProperties to link it with Spring’s configuration system.

2.5 Access Configuration in the Spring Boot Application

With the Java classes generated, you can now inject the configuration into your spring boot component. Below is a service class that retrieves the list of endpoints from the injected AppConfig object and prints their details.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
import org.springframework.stereotype.Service;
 
@Service
public class EndpointService {
 
    private final AppConfig appConfig;
 
    public EndpointService(AppConfig appConfig) {
        this.appConfig = appConfig;
    }
 
    public void printEndpoints() {
        appConfig.getServer().getEndpoints().forEach(endpoint ->
            System.out.println("Name: " + endpoint.getName() + ", Port: " + endpoint.getPort())
        );
    }
}

The code defines a Spring service class called “EndpointService” with a constructor that accepts an “AppConfig” object, which is injected by Spring. The class has a method “printEndpoints()” that retrieves the list of endpoints from the “Server” object within the “AppConfig”. It then iterates over each endpoint and prints its name and port to the console. This service is designed to handle and display the endpoint configuration from the provided app configuration.

2.6 Expose Configuration via a Spring Boot Controller

Create a controller to expose the Pkl configuration via REST API.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.example.config.AppConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.List;
 
@RestController
@RequestMapping("/config")
public class ConfigController {
 
    private final AppConfig appConfig;
 
    public ConfigController(AppConfig appConfig) {
        this.appConfig = appConfig;
    }
 
    @GetMapping("/endpoints")
    public List<AppConfig.Endpoint> getEndpoints() {
        return appConfig.getEndpoints();
    }
}

The code defines a Spring REST controller named “ConfigController” with a request mapping of “/config”. The controller has a constructor that injects the “AppConfig” object. It includes a method “getEndpoints()” mapped to the HTTP GET request “/endpoints”. This method returns a list of “Endpoint” objects from the “AppConfig” class, providing access to the server’s configured endpoints via a RESTful API.

2.7 Enable Pkl configuration Binding

Update the application.yml file to ensure Spring Boot recognizes the Pkl configuration.

1
2
3
spring:
  config:
    import: "classpath:/application.pkl"

2.8 Application Entry Point

Create a Spring Boot main class to start the application.

01
02
03
04
05
06
07
08
09
10
11
package com.example;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class PklSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(PklSpringBootApplication.class, args);
    }
}

2.9 Run the application

To start the Spring Boot application, run the following command:

1
./gradlew bootRun

Once the application is running, you can make a HTTP GET request to retrieve the configured endpoints using the following curl command:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
-- HTTP GET endpoint
 
-- Output response
[
    {
        "name": "API-Gateway",
        "port": 8080
    },
    {
        "name": "User-Service",
        "port": 9090
    }
]

3. Conclusion

In this article, we’ve demonstrated how to integrate Pkl (Pickle) configuration with a Spring Boot application. By leveraging Pkl’s powerful configuration-as-code approach, we not only manage application settings efficiently but also enhance the maintainability and flexibility of our application configuration.

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button