January 07, 2026

Hexagonal Architecture

Abstract

Hexagonal Architecture is a source code architecture pattern; it is a pattern for organizing your platform’s source code. Also known as Ports and Adapters Architecture, it is a software architectural pattern which separates an application’s core business logic (source code) from external systems or technologies such as databases, user interfaces, or third-party services. The goal of Hexagonal Architecture is to make the core business logic source code independent of any external systems, ensuring the source code remains flexible, maintainable, and testable. Alistair Cockburn documented the Hexagonal Architecture (ports and adapters) in a work published in 2005 (Wikipedia). Cockburn stated the intent of the architecture is:

“Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.”

This post summarizes Hexagonal Architecture. It is a guide for those with previous knowledge of this architecture. The roles, responsibilities, and characteristics of each hexagonal layer are described. Finally, an example pattern for organizing your source code is presented.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Overview

An overview of Hexagonal Architecture is shown in Figure 2.1.

Figure 2.1 – Hexagonal Architecture Overview (Artisan image)

Hexagonal Architecture Overview
Hexagonal Architecture Overview

Framework is the outermost layer and defines which drivers are supported. A driver is a means of communicating with one of the Frameworks. Common drivers are (a) HTTPS & web browser, (b) JMS & messaging, and (c) SFTP & data files. A Framework has one responsibility which is to adopt requests and responses between the driver and the Application.

Application is the middle layer and defines interactions with the Domain. The Application has two responsibilities.

  1. Coordinate Domain operations to fulfill whatever request came in through the Framework. For example, a single request may require the execution of multiple Domain operations, which the Application would coordinate.

  2. Implement Domain interactions with external resources. For example, the Domain may need purchase order data, which the Application is responsibility for getting on the Domain’s behalf. The Domain is indifferent to the implementation details of interactions with external resources, allowing the Application to update as needed; database one day, API the next.

Domain is the core layer and defines the business. The Domain has one responsibility which is to implement business features.

Further information about each hexagonal layer is provided next.

Domain

The Domain is the core hexagon. Its purpose is to implement all business processes and to abstract all external resources (data) needed to accomplish it. The Domain is free of any Framework details (HttpServletRequest, Session, RestTemplate, etc.) and Application details (JDBC, JMS, REST, etc.).

Figure 3.1 – Domain (Artisan image)

Domain
Domain

The Domain IS your application. The scope of the Domain code is the business requirements, and it implements these details. Anything other than this is abstracted by a Domain secondary port - an interface. This interface is later implemented in the Application. For example, to use purchase order data, the Domain defines an interface to abstract its retrieval. This interface is a Domain secondary port. This interface is implemented in the Application by an appropriate means like querying a database, reading a file, or calling an API.

The Domain receives no raw requests from drivers (HTTPS, SFTP, etc.). Domain primary ports are classes which define communication with the Domain without any driver details.

Domain Model

A model based on DDD object types implements the core business logic of the Domain. The following are common, but not an exhaustive list of Domain model objects.

  • Entity. An object that is not defined by its attributes, but rather by a thread of continuity and its identity (i.e. primary key) Example: Most airlines distinguish each seat uniquely on every flight. Each seat is an entity in this context. However, some airlines do not distinguish between every seat; all seats are the same. In this context, a seat is a value object.

  • Value object. An object that contains attributes but has NO identity (i.e. no primary key). They should be treated as immutable. Example: (1) S, M, L, XL, XXL, (2) Red, Green, Blue, and (3) Name. These are values that are part of an entity but are not uniquely identifiable by themselves (i.e. no primary key). A person’s name may be stored as a String or a custom Name inside an Entity. This Name object would be a value object.

  • Aggregate. A collection of objects that are bound together by a root entity, otherwise known as an aggregate root. An aggregate does NOT have its own unique identity (primary key) as it is a collection of separate entities. The aggregate root guarantees the consistency of changes (ACID) being made within the aggregate by defining a transactional boundary for all Entity objects it contains. Example: When you drive a car, you do not have to worry about moving the wheels forward, making the engine combust with spark and fuel, etc.; you are simply driving the car. In this context, the car is an aggregate of several other objects and serves as the aggregate root to all the other systems.

  • Factory. Methods for creating Domain objects should be delegated to a specialized Factory object such that alternative implementations may be easily interchanged. A Factory is for creating in-memory objects, not persistence.

  • Command. A Command is a user-initiated operation which may be rejected or accepted. If REJECTED, then command processing stops and nothing happens. If ACCEPTED, then command processing continues, and a Domain task/operation occurs. In either case (accepted or rejected) a Domain Event may be published.

  • Service. When an operation does not conceptually belong to any object. Following the natural contours of the problem, you can implement these operations in services.

  • Event. A Domain object that defines a Domain event; something that happened in the past. A Domain Event is an event that Domain experts care about.

  • Publisher. Methods for publishing Domain Events should be delegated to a specialized Publisher object such that alternative publication implementations may be easily interchanged. No implementation details are in the Domain. The Application is responsible for implementing (JMS, SFTP, SMTP, etc.) the publication.

  • Repository. Methods for retrieving Domain objects should be delegated to a specialized Repository object such that alternative storage implementations may be easily interchanged. No implementation details are in the Domain. The Application is responsible for implementing (SQL, data file, REST API, etc.) the repository to provide the data.

  • Sender. Methods for sending Domain objects should be delegated to a specialized Sender object such that alternative sending implementations may be easily interchanged. No implementation details are in the Domain. The Application is responsible for implementing (email, SMS) the sender.

Domain Primary Ports

A Domain primary port is an entry point into the Domain. An entry point is any inbound interaction with the Domain by the outer layers, almost always the Application. A Domain primary port has the following characteristics:

  • It is a concrete class.
  • It defines operations used by the Application to interact with the Domain.
  • It is implemented in the Domain by using:
    • Command objects
    • Service objects
  • It is injected into an Application primary adapter.

Figure 3.2.1 – Domain Primary Port UML

Domain Primary Port UML
Domain Primary Port UML

Domain Secondary Ports

A Domain secondary port is an exit point out of the Domain. An exit point is any outbound interaction with external systems or resources. A Domain secondary port has the following characteristics:

  • It is an interface.
  • It defines interactions with an external system or resource such as a database, message broker, file system, API, etc.
  • It is NOT implemented by the Domain.
  • It IS implemented by an Application secondary adapter.
    • There may be multiple implementations.
  • Different implementations should be easy to use.

Figure 3.3.1 – Domain Secondary Port UML

Domain Secondary Port UML
Domain Secondary Port UML

Application

The Application is the hexagon wrapping the Domain. It has two purposes.

  1. Instantiate instances of Domain primary port classes, injecting them as dependencies into Application primary adapters.
  2. Implement the Domain secondary port interfaces as Application secondary adapters. The Domain is indifferent to the implementation details of these interfaces by the Application (database, file, rest, etc.), so long as the implementations fulfill the interface contract.

The Application is free of any Framework details (HttpServletRequest, Session, RestTemplate, etc.).

Figure 4.1 – Application (Artisan image)

Application
Application

Application Primary Adapters

An Application primary adapter instantiates and uses one or more Domain primary port classes to orchestrate and perform Domain-related operations. An Application primary adapter has the following characteristics:

  • It is a class.
  • It is injected with instances of Domain primary ports (classes) which are the entry points into the Domain.
  • It orchestrates the Domain primary ports (classes) to carry out Domain-related operations.

Application Secondary Adapters

An Application secondary adapter implements the Domain secondary port interfaces. How the Application implements the interface is not important to the Domain, provided it adheres to the interface contract. An Application secondary adapter has the following characteristics:

  • It is a class.

  • Implements a Domain secondary port which are the exit points of the Domain. The Application can implement the interface as needed (database, messaging, rest API, file, messaging, etc.).

  • Injected wherever a Domain secondary port is needed.

Application Primary Ports

An Application primary port is like a Domain primary port. An Application primary port is an entry point into the Application. An entry point is any inbound interaction with the Application by the outer layers, typically a Framework. An Application primary port has the following characteristics:

  • It is a concrete class.
  • It is implemented in the Application by using:
    • Command objects
    • Service objects
  • Defines operations used by the Framework to interact with the Application.
  • Translates the Application “language” into the Domain “language”.
  • Injected into a Framework primary adapter.

Framework

The Framework is the hexagon wrapping the Application. Its purpose is to adapt raw requests from drivers (users/HTTP, messages/JMS, files/SFTP, etc) to the Application.

Multiple Frameworks may exist, and they will use the same Application and Domain. For example, a website user and a marketing company both want to see the same data. The website user’s driver will be a web browser which will interact with a Framework capable of returning HTML. The marketing company’s driver will be a REST API which will interact with a different Framework capable of returning JSON. Since both Frameworks use the same Application and Domain, both return the same data.

Figure 5.1 – Frameworks (Artisan image)

Frameworks
Frameworks

Framework Primary Adapters

A Framework primary adapter instantiates and uses one or more Application primary port classes to adapt raw requests from drivers to the “language” of the Application layer. A Framework primary adapter has the following characteristics:

  • It is a class.
  • Injected with instances of Application primary ports which are the entry points into the Application.
  • Translates the raw driver “language” into the Application “language”. Common drivers are (a) HTTPS & web browser, (b) JMS & messaging, and (c) SFTP & data files.

Driver

A Driver exists outside of the hexagon. A Driver communicates with a Framework using a specific protocol and the Framework listens to requests on that protocol.

For example, a Driver can be a JavaScript framework (Angular, React, Vue, etc.) communicating with a Framework by HTTPS. This Framework uses @Path("helloworld") and @GET or @POST (Building RESTful Web Services with Jakarta REST, n.d.) to listen for HTTPS requests. Once an HTTPS request is received by the Framework, it is translated to Application-defined objects and handed off to the Application handler for processing. Multiple Framework projects may exist to support Drivers using different protocols. Common drivers are (a) HTTPS & web browser, (b) JMS & messaging, and (c) SFTP & data files. The different Frameworks hand off processing to the same Application and Domain, allowing access to the same business features.

Figure 6.1 shows this with 4 different raw drivers each supported by their own Framework. All the Frameworks, however, share the Application and Domain.

Figure 6.1 – Drivers (Artisan image)

Drivers
Drivers

Example Source Code Organization

Suppose the ABC Sales Report business feature is needed.

NOTE A feature (aka “business feature”) implements one and only one business process which supports the platform’s underlying business goals.

First, create a new source code repository with the following name:

abc-sales-report

Next, follow the Hexagonal Architecture pattern and create sub-folders based on the hexagon layers. Physically these are file system folders created on the file system inside the repository. Logically these folders have different names depending on the technology you are using. If you are using Java and Maven, you may refer to these folders as modules of a project. If you are using C# and Visual Studio, you may refer to these folders as projects of a solution. For this example, I will refer to them as modules. The names of the modules both identify the hexagon layer the code is related to and declare the intent of the code. For example, abc-sales-report repository may have the following modules:

/abc-sales-report
    /api
    /jms
    /application
    /domain
    /ui

Here is a description of each module:

/api A Hexagonal Architecture Framework module containing REST endpoints. Provides a way the outside world may interact with the Domain. Responsible for translating HTTPS requests into Application objects for processing.

/jms A Hexagonal Architecture Framework module containing messaging Java (JMS) listeners. Provides a way the outside world may interact with the Domain. Responsible for translating Java JMS messages into Application objects for processing.

NOTE You may be asking, “Why not name the module ‘framework’ and put all framework layer code in one module?” Recall from 6.1, there may be many different raw drivers that want to communicate with your platform and each raw driver will use a different protocol for communication. Following Hexagonal Architecture, separate the raw driver protocol handlers into different modules so each module is only responsible for translating its raw driver “language” into the application layer “language”. This is done so that ultimately the Domain can handle processing the request. Each deployment will include the Application and Domain code.

/application A Hexagonal Architecture Application module containing Domain orchestration and Domain secondary port (exit points) interface implementations. These implementations provide a way the Domain may interact with the outside world.

/domain A Hexagonal Architecture Domain module containing the business feature code. This layer should have no knowledge of the Framework or Application code. It should be easily testable without any external runtime environments and easily reusable as Framework or Application layer code is changed.

/ui A UI raw driver. Think single-page application technology like Angular. Responsible for translating user input into HTTPS (typically) to interact with the Framework /api module for requests.

Everything for the abc-sales-report is contained in a single repository. This helps the code adhere to the characteristics of Feature-Oriented (modular) Architecture.

NOTE These characteristics are the same as microservices. However, the word “microservice” is meaningless and its use should be avoided.

These “microservice” characteristics (Ma, medium, 2018) match up with Hexagonal Architecture in the following ways:

  1. Single purpose. The name of the repository is abc-sales-report. The name defines its purpose. If the code is doing anything other than supporting this report, the platform developers got the code wrong.

  2. Loose coupling. The Application code which implements the Domain secondary port (exit points) keeps coupling loose. If not, the platform developers got the code wrong.

  3. High cohesion. If you need to make a change to the ABC Sales Report, it should be clear this repository is the only place you need to go. If not, the system platform developers got the code wrong.

References

Cockburn, A. (n.d.). Hexagonal architecture. Alistair Cockburn. https://alistair.cockburn.us/hexagonal-architecture/. Cockburn’s original post.

Hexagonal architecture. (n.d.). https://fideloper.com/hexagonal-architecture. Description of the hexagon and the responsibilities of each layer.

Ports-And-Adapters. (n.d.). https://www.dossier-andreas.net/software_architecture/ports_and_adapters.html. Definition of primary ports, secondary ports, primary adapters, and secondary adapters.

Jfokus. (2020, February 16). Cubes, hexagons, triangles, and more: Understanding Microservices by Chris Richardson [Video 21:26 - 26:34 (5 minutes)]. YouTube. https://www.youtube.com/watch?v=rMDjuXTQVkk. Chris Richardson’s JFocus 2020 Presentation on Microservices with includes a brief overview of hexagonal architecture.

Wikipedia contributors. (2025, February 18). Domain-driven design. Wikipedia. https://en.wikipedia.org/wiki/Domain-driven_design. Domain driven design (DDD) list of common model object names and responsibilities.

Karol.Kuc. (2020, May 20). Hexagonal Architecture by example - a hands-on introduction. blog.allegro.tech. https://blog.allegro.tech/2020/05/hexagonal-architecture-by-example.html. Practical code example demonstrating package structure, class naming conventions, and how interfaces and implementations get put into the different layers.

Dziadeusz. (n.d.). GitHub - dziadeusz/hexagonal-architecture-by-example. GitHub. https://github.com/dziadeusz/hexagonal-architecture-by-example. Practical code example demonstrating package structure, class naming conventions, and how interfaces and implementations get put into the different layers.

Ma, Xiao. (2018, October 17). Microservice Architecture at Mediumhttps://medium.engineering/microservice-architecture-at-medium-9c33805eb74f.

Building RESTful Web Services with Jakarta REST :: Jakarta EE Tutorial :: Jakarta EE Documentation. (n.d.). https://jakarta.ee/learn/docs/jakartaee-tutorial/current/websvcs/rest/rest.html

August 15, 2025

JDK 25 - JEP 503: Remove the 32-bit x86 Port

Abstract

JDK 25 - JEP 503: Remove the 32-bit x86 Port. JEP 503 does not introduce any new language features. The JEP specifies Java will no longer support 32-bit hardware. The cost of maintaining a 32-bit port of Java is very costly with little benefit since 32-bit is no longer prevalent.

Pure Speculation

In 1996, the Nintendo 64 game console was released. This was the first big “64-bit” thing that I remember. As of this writing (2025), that was 29 years ago. So, maybe in the year 2054, There will be a JEP to remove support for the 64-bit x86 port in favor of continued development of the Quantum port (pure speculation)!

Nintendo 64
Nintendo 64

References

Shipilev, A. (2024, November 28). JEP 503: Remove the 32-bit x86 Port. https://openjdk.org/jeps/503.

JDK 25 - JEP 502: Stable Values (Preview)

Abstract

JDK 25 - JEP 502: Stable Values (Preview). This JEP introduces an API for stable values, which are objects that hold immutable data. Stable values are treated as constants by the JVM, enabling the same performance optimizations that are enabled by declaring a field final. Compared to final fields, however, stable values offer greater flexibility as to the timing of their initialization.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • openjdk 25-ea 2025–09–16 (build 25-ea+27–3363)
  • NetBeans 25
  • Maven 3.9.6 (Bundled with NetBeans)
  • maven-compiler-plugin-3.14.0

Download

Visit my GitHub page https://github.com/mjremijan to see all of my open source projects. The code for this post is located at https://github.com/mjremijan/thoth-jdk25

Compile and Run

This is a preview API, disabled by default. To use this API in JDK 25, you must enable preview APIs:

  • Compile the program with javac --release 25 --enable-preview Main.java and run it with java --enable-preview Main
  • When using the source code launcher, run the program with java --enable-preview Main.java
  • When using jshell, start it with jshell --enable-preview

A Traditional Logger

A Logger object is a good example to introduce JEP 502: Stable Values. Ideally, creating a Logger object should have the following characteristics:

  1. Created one time only
  2. Created only when needed (lazy initialization)
  3. Immutable
  4. Optimization by the JVM (code in-lining, etc)

The traditional way to create a Logger is through a class-level final property. Listing 1 demonstrates this.

Listing 1 - Traditional Logger with Eager Initialization

package org.thoth.jdk25.jep502.main.traditional;

import java.util.logging.Logger;

public class TraditionalLoggerWithEagerInitialization {
  private static final Logger log
    = Logger.getLogger(TraditionalLoggerWithEagerInitialization.class.getName());
  
  public void service() {
      log.info("service() method start");
  }
}

This code is good, but it has eager initialization. The Logger object is created whether or not it is ever used. While creating this logger may be a fast operation, it is easy to imagine an expensive object creation composed of many different objects using external resources which either need to be created or connected to. It would be better if the initialization was on-demand (lazy). Listing 2 demonstrates this.

Listing 2 - Traditional Logger with Lazy Initialization

package org.thoth.jdk25.jep502.main.traditional;

import java.util.logging.Logger;

public class TraditionalLoggerWithLazyInitialization {
  private static Logger log;
  
  private static Logger getLog() {
    if (log == null) {
      log = Logger.getLogger(TraditionalLoggerWithLazyInitialization.class.getName()); 
    }
    return log;
  }
  
  public void service() {
      getLog().info("service() method start");
  }
}

This code implements lazy initialization, but introduces other problems. Threading is the first obvious issue. Threading potentially allows multiple loggers to be created. The possibility for multiple instances means the JVM cannot treat this object as immutable and thus cannot fully optimize its use. This may be addressed with synchronization, but mutli-threaded code is tricky to get right. This code also introduces a subtle NullPointerException issue because if the getLog() method is not used 100% of the time then it is possible the log property is null. Accessing the Logger through the getLog() method is not ideal.

Neither of these traditional ways of creating a Logger have all of the characteristics we want for initializing the object. The purpose of JEP 502 is to address these issues. Let’s start looking at JEP 502.

StableValue<M>

StableValue<M> has been introduced to the JVM in JEP 502: Stable Values (Preview). Its purpose is to:

  1. Hold immutable data
  2. Treated as constants by the JVM, enabling the same performance optimizations that are enabled by declaring a field final
  3. Offer greater flexibility as to the timing of their initialization

The goal is to have the JVM handle the creation of these objects until they are needed. Since they are immutable, the JVM is able to optimize the bytecode for execution. Listing 3 shows the most basic use of StableValue.

Listing 3 - StableValue Logger

package org.thoth.jdk25.jep502.main.proposed;

import java.util.logging.Logger;

public class StableValueLogger {
  private final StableValue<Logger> logger = StableValue.of();

  Logger getLog() {
    return logger.orElseSet(() -> Logger.getLogger(StableValueLogger.class.getName()));
  }

  public void service() {
    getLog().info("service() method start");
  }
}

On line 6, see that the logger property is no longer a Logger instance but a StableValue<Logger> instance instead. The getLog() method calls the StableValue.orElseSet() method. The supplied lambda to this method knows how to create the Logger when needed. The orElseSet() method guarantees the lambda is evaluated only once even in a multi-threaded environment.

While using StableValue<Logger> results in a guaranteed single instance and thread safety, it unfortunately means accessing the Logger through the getLog() method to initialize the Logger object and return it. If getLog() is not used, there is no risk of a NullPointerException, but, using the StableValue API methods directly every time a Logger was needed would be very verbose and ugly. It would be more convenient if the logger property could be used more directly. This can be accomplished using a stable supplier. Listing 4 demonstrates this.

Listing 4 - Stable Supplier Logger

package org.thoth.jdk25.jep502.main.proposed;

import java.util.function.Supplier;
import java.util.logging.Logger;

public class StableSupplierLogger {
  private final Supplier<Logger> logger 
    = StableValue.supplier(() -> Logger.getLogger(StableSupplierLogger.class.getName()));

  public void service() {
    logger.get().info("service() method start");
  }
}

On line 7, see that the logger property is no longer a Logger instance but a Supplier<Logger> instance instead. The lambda passed to StableValue.supplier() is responsible for creating a Logger when evaluated.

On line 11, see that the Supplier.get() method is called. Similar to the orElseSet() method, the lambda is guaranteed to evaluate only once even in a multi-threaded environment. While using the Supplier.get() method is still an intermediary step needed to get the Logger, using this instance method is a better user experience than using a custom private getLog() method.

Summary

This has been a quick look into JEP 502: Stable Values (Preview). It is a new API, giving the JVM the ability to manage the creation of immutable objects. Having the JVM manage the creation of the objects conserves resources by creating objects only when needed and optimizes performance by treating them as final constant values. This is a preview feature so look for it to be finalized in a future release.

References

Minborg, P., Cimadamore, M. (2023, July 24). JEP 502: Stable Values (Preview). https://openjdk.org/jeps/502.

July 29, 2025

JDK 25 - JEP 470: PEM Encodings of Cryptographic Objects (Preview)

Abstract

JDK 25 - JEP 470: PEM Encodings of Cryptographic Objects (Preview). The Privacy-Enhanced Mail (PEM) format https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail defined by RFC 7468 https://www.rfc-editor.org/rfc/rfc7468 is a representation of cryptographic objects. This JEP adds encoding and decoding of the PEM format to Java.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • openjdk 25-ea 2025–09–16 (build 25-ea+27–3363)
  • NetBeans 25
  • Maven 3.9.6 (Bundled with NetBeans)
  • maven-compiler-plugin-3.14.0

Download

Visit my GitHub page https://github.com/mjremijan to see all of my open source projects. The code for this post is located at https://github.com/mjremijan/thoth-jdk25

Compile and Run

This is a preview API, disabled by default. To use this API in JDK 25, you must enable preview APIs:

  • Compile the program with javac --release 25 --enable-preview Main.java and run it with java --enable-preview Main;
  • When using the source code launcher, run the program with java --enable-preview Main.java;
  • When using jshell, start it with jshell --enable-preview.

Java Generate public/private PEM files

Create a Java KeyPair and generate the public/private keys in PEM format.

Listing 1 - Java Generate Keys in PEM Format

package org.thoth.jdk25.jep470.main;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PEMEncoder;
import java.security.SecureRandom;

/**
 */
public class MainInMemoryEncoding {

  public static void main(String[] args) throws Exception {
    System.out.printf("Hello JEP-470 In memory encoding!%n%n");
    
    System.out.printf("Create KeyPairGenerator for RSA%n");
    KeyPairGenerator generator 
      = KeyPairGenerator.getInstance("RSA");
    
    System.out.printf("Initialize KeyPairGenerator with a key size and SecureRandom%n");
    generator.initialize(2048, new SecureRandom());
    
    System.out.printf("Generate a KeyPair%n");
    KeyPair pair
      = generator.generateKeyPair();
    
    System.out.printf("Create PEMEncoder%n");
    PEMEncoder pe = PEMEncoder.of();
    
    System.out.printf("Encode private key to the PEM format%n");
    String privatePem = pe.encodeToString(pair.getPrivate());
    System.out.printf("%s%n", privatePem);
    
    System.out.printf("Encode public key to the PEM format%n");
    String publicPem = pe.encodeToString(pair.getPublic());
    System.out.printf("%s%n", publicPem);
  }
}

OpenSSL Generate public/private PEM files

Use the following Linux commands to generate public/private keys in PEM format saved to files.

Listing 2 - Generate 2048-bit RSA private key PEM file

openssl genrsa -out test-private.pem 2048

Listing 3 - Extract RSA public key PEM file

openssl rsa -in test-private.pem -out test-public.pem -pubout -outform PEM

Java read public OpenSSL PEM file

Read the test-public.pem file.

Listing 4 - Read test-public.pem

package org.thoth.jdk25.jep470.main;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.DEREncodable;
import java.security.PEMDecoder;
import java.security.PublicKey;

/**
 */
public class MainOpenSSLDecodingPublicFile {

  public static void main(String[] args) throws Exception {
    System.out.printf("Hello JEP-470! OpenSSL decoding public PEM file%n%n");
    
    System.out.printf("Read the OpenSSL test-public.pem file into a String%n");    
    InputStream is = MainOpenSSLDecodingPublicFile.class.getClassLoader().getResourceAsStream("test-public.pem");
    byte[] bytes = is.readAllBytes();
    String publicPem = new String(bytes, StandardCharsets.UTF_8);
    System.out.printf("%s%n", publicPem);
    
    System.out.printf("Create PEMDecoder%n");
    PEMDecoder pd = PEMDecoder.of();

    System.out.printf("Decode the OpenSSL test-public.pem file%n");
    DEREncodable derEncodable = pd.decode(publicPem);
    switch (derEncodable) {
      case PublicKey publicKey -> System.out.printf("Successfully decoded PublicKey!%n");  
      default -> System.out.printf("What is \"%s\"%n", derEncodable.getClass().getName());
    }      
  }
}

Java read private OpenSSL PEM file

Read the test-private.pem file.

Listing 5 - Read test-private.pem

package org.thoth.jdk25.jep470.main;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.DEREncodable;
import java.security.PEMDecoder;
import java.security.PrivateKey;

/**
 */
public class MainOpenSSLDecodingPrivateFile {
    public static void main(String[] args) throws Exception {
     System.out.printf("Hello JEP-470! OpenSSL decoding private PEM file%n%n");
     
     System.out.printf("Read the OpenSSL test-private.pem file into a String%n");
     InputStream is = MainOpenSSLDecodingPrivateFile.class.getClassLoader().getResourceAsStream("test-private.pem");
     byte[] bytes = is.readAllBytes();
     String privatePem = new String(bytes, StandardCharsets.UTF_8);
     System.out.printf("%s%n", privatePem);

     System.out.printf("Create PEMDecoder%n");
     PEMDecoder pd = PEMDecoder.of();
     
     System.out.printf("Decode the OpenSSL test-private.pem file%n");
     DEREncodable derEncodable = pd.decode(privatePem);
     switch (derEncodable) {
      case PrivateKey privateKey -> System.out.printf("Successfully decoded PrivateKey!%n");    
      default -> System.out.printf("What is \"%s\"%n", derEncodable.getClass().getName());
     }
  }
}

Summary

JEP 470 add PEM encoding and decoding functionality to Java. In JDK 25, it is a preview feature so look for it to be finalized in a future release.

References

Scarpino, A. (2023, January 23). JEP 470: PEM Encodings of Cryptographic Objects (Preview). https://openjdk.org/jeps/470

May 07, 2025

Email Notes to OneNote with IFTTT

Abstract

Microsoft officially retired the me@onenote.com email feature on March 26, 2025. This service previously allowed users to forward emails directly into their OneNote notebooks by sending them to that address.

The decision to discontinue this feature was due to low usage and the availability of more integrated alternatives. Microsoft recommends using the “Send to OneNote” feature within Outlook, which allows users to send emails and meeting invitations directly to specific OneNote notebooks and sections.

Unfortunately, I am one of those “low usage” people. I relied quite heavily on the me@onenote.com email feature. Using the “Send to OneNote” feature within Outlook of course is not remotely the same thing and an attempt by Microsoft to force people to Outlook for email.

Fortunately, I found a very simple and easy solution: IFTTT

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following IFTTT Applets available as of May 7, 2025.

  • “Forward important emails to OneNote”

Add and Configure IFTTT Applet

Login to IFTTT

Click the “Explore” button

Search for “Forward important emails to OneNote”. It is an IFTTT Applet that looks like this:

Figure 1 - IFTTT Applet

IFTTT Applet
IFTTT Applet

Click “Connect” to get started with configuring this applet.

Figure 2 - IFTTT Connect Button

IFTTT Connect Button
IFTTT Connect Button

Once it is connected, configure the OneNote part of the applet so a new note is created in the Notebook and Section you want. In the example below, New notes will be created in my “Process” notebook inside the “Collect” section.

Figure 3 - IFTTT OneNote Configuration

IFTTT OneNote Configuration
IFTTT OneNote Configuration

Once this is all done, send an email to “trigger@applet.ifttt.com” and emails will show up in OneNote.

Summary

Use IFTTT to fill in the gap with Microsoft ending support for me@onenote.com.

February 04, 2025

arch42 Stakeholders for Software

Abstract

arch42 has a section to document the stakeholders of the platform. Stakeholders have different roles and expectations when interacting with the platform’s architecture documentation. The purpose of this post to describe a few common roles and how they relate to each other.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

A solution architect documenting the roles and expectations of stakeholders for the platform.

Roles

There are many people involved with the platform. Each person has a particular role and expectation with respect to the platform architecture and its documentation. People may have many roles. ChatGPT was initially prompted with “in software development if the analyst owns the what and the architect owns the how, what does the developer own?”. It was then prompted with the follow-ups “what does the tester own?” and “what does the user own?”. Responses were used to describe roles and expectations.

Owner. The owner is expected to provide the platform team decisions about (a) underlying business goals, (b) platform features and functional (business) requirements, and (c) platform architecture and non-functional (quality) requirements.

Analyst. The analyst is expected to provide the platform team with fully documented functional (business) requirements of the platform features in fulfillment of the underlying business goals. The analyst owns the “what” of the platform’s operation and maintains it in the architecture documentation.

Architect. The architect is expected to provide the platform team with fully documented non-functional (quality) requirements of the platform features in fulfillment of the underlying quality goals. The architect owns the “how” of the platform’s operation and maintains it in the architecture documentation.

Developer. The developer is expected to provide the platform team with an implementation of the platform in fulfillment of both the functional (business) and non-functional (quality) requirements specified by the analyst and architect respectively. The developer owns the “do” of the platform’s operation and references the architecture documentation.

Tester. The tester is expected to provide the platform team with quality assurance of the platform in fulfillment of both the functional (business) and non-functional (quality) requirements specified by the analyst and architect respectively. The tester owns the “validate” of the platform’s operation and references the architecture documentation.

User. The user is expected to provide the platform team with feedback on the platform. The user owns the “experience” of the platform’s operation with no direct use of the architecture documentation.

No list like this can be exhaustive, but, for most platforms this is a good list of roles to start with. Update the expectations or add new roles as appropriate for your platform.

Summary

That’s it, enjoy!

References

arc42 Documentation. (n.d.). https://docs.arc42.org/home/

ISO 25010. (n.d.). https://iso25000.com/index.php/en/iso-25000-standards/iso-25010

OpenAI. (2025). ChatGPT (Feb 04 version) [Large language model]. https://chatgpt.com/

arch42 Quality Goals for Software Architects

Abstract

arch42 has a section to document the quality goal decisions of your system or software product. arch42 references the ISO 25010. This a great standard reference for solution architects to focus on the non-functional requirements important to the stakeholders. The purpose of this post is to show the ISO 25010 standard characteristics and sub-characteristics.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

A solution architect working with stakeholders to document the 3–5 most important quality goal characteristics for a system or software product.

ISO 25010

Visit ISO 25010 to read more about the characteristics and sub-characteristics for product quality. Table 1 provides a summary. In general, these are all of the “-ility” statements.

Table 1 - ISO 25010 Quality Characteristics

Functional Stability Performance Efficiency Compatibility Interaction Capability Reliability Security Maintainability Flexibility Safety
Functional Completeness

Functional Correctness

Funcational Appropriateness
Time Behavior

Resource Utilization

Capacity
Co-Existence

Interoperability
Appropriateness Recognizability

Learnability

Operability

User Error Protection

User Engagement

Inclusivity

User Assistance

Self-Descriptiveness
Faultlessness

Availability

Fault Tolerance

Recoverability
Confidentiality

Integrity

Non-Repudiation

Accountability

Authenticity

Resistance

Compliance
Modularity

Reusability

Analysability

Modifiability

Testability
Adaptability

Scalability

Installability

Replaceability
Operational Constraint

Risk Identification

Fail Safe

Hazard Warning

Safe Integration

When deciding the quality goals used to architect and evaluate the system or software product, they should be listed as both characteristics and sub-characteristics as shown in Table 1.

Summary

That’s it, enjoy!

References

arc42 Documentation. (n.d.). https://docs.arc42.org/home/

ISO 25010. (n.d.). https://iso25000.com/index.php/en/iso-25000-standards/iso-25010

January 14, 2025

Apache Derby Database Select-for-Update

Abstract

Select-for-update is an SQL feature which I used to use all the time, but it seems like it’s use has fallen out of favor. However, there are valid use cases for it.

My ferris-resiste project is an RSS to email system. The system keeps track of all RSS entries it encounters to prevent emailing duplicates. However, how long do you keep this history of RSS entries? RSS data isn’t 100% reliable, so the system has its own way of determining when to delete RSS entries. Each time an RSS entry is encountered, the date it’s encountered is saved in the database. If an RSS entry isn’t encountered, that date isn’t updated. Deleting RSS entries is then a simple query which use this last encountered date to delete entries older than 6 months. If the RSS feed hasn’t had that RSS entry for the past 6 months, it’s probably safe to assume the system will not encounter it again.

This is a perfect use case for a select-for-update SQL statement. The purpose of this post is to demonstrate how a select-for-update statement works for the Apache Derby database.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Code

Listing 1 is Java code demonstrating select-for-update for Apache Derby.

Listing 1 - Java select for update code for Apache Derby

public Optional<RssHistory> find(String feedId, String entryId) {
  
  log.info(String.format("Find RSS entry history feedId=\"%s\", entryId=\"%s\"", feedId, entryId));
  
  Optional<RssHistory> retval
    = Optional.empty();

  StringBuilder sp = new StringBuilder();
  sp.append(" select ");
  sp.append("     feed_id, entry_id, published_on, last_found_on ");
  sp.append(" from ");
  sp.append("     rss_entry_history ");
  sp.append(" where ");
  sp.append("     feed_id=? ");
  sp.append("     and ");
  sp.append("     entry_id=? ");
  sp.append(" for update of ");
  sp.append("     last_found_on ");

  PreparedStatement stmt = null;
  ResultSet rs = null;
  try {
    stmt = conn.prepareUpdatableStatement(sp.toString());
    
    stmt.setString(1, feedId);
    stmt.setString(2, entryId);

    rs = stmt.executeQuery();
    if (rs.next()) {
      retval = Optional.of(
        new RssHistory(feedId, feedId, rs.getTimestamp("published_on").toInstant())
      );
      
      rs.updateDate(4, Date.valueOf(LocalDate.now()));
      rs.updateRow();
    }

  } catch (Throwable t) {
    throw new RuntimeException(
      String.format("Problem finding feed entry in history table feedId=\"%s\", entryId=\"%s\", sql=\"%s\""
        , feedId, entryId, sp.toString()
      ), t
    );
  } finally {
    conn.close(stmt, rs);
  }

  return retval;
}

Lines 17,18 These lines make this a select-for-update query. Line 18 specifies the last_found_on field is being updated.

Line 23 Uses the prepareUpdatableStatement() method to get a Statement object.

Line 34 Uses the updateDate() method to set the new value for the last_found_on field.

Line 35 Uses the updateRow() method to save the updated data to the database within the select-for-update and without having to execute a separate update statement.

Summary

That’s it. Pretty simple. I hope you enjoyed learning how to run a select-for-update SQL statement in Apache Derby.

October 03, 2024

Apache Derby Database Series

Abstract

This is my series on the Apache Derby Database. Move beyond its basics and use a great database for your applications.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Summary

That’s it. I hope you enjoy using Apache Derby!

March 11, 2023

Using PrismJS in Blogger for Code Highlighting

Abstract

For my blog, since I write mostly about technology and specifically software development, I needed a syntax highlighter for styling my source code examples.

I first started using SyntaxHighlighter to style source code. SyntaxHighligher works by add a class to a <pre> tag like this:

<pre class=“brush: java”>

This worked well until I started writing my blog posts using Scrivener. With Scrivener, I write in Markdown and Scrivener compiles to HTML for me. The standard HTML to use for source code is a <pre> tag surrounding a <code> tag like this:

<pre><code class=“java”>

Unfortunately, SyntaxHighligher does not support this HTML so it no longer worked for me.

I then started using Highlight.js. This tool has been working well, but its styling is a little too simple. Plus I really wanted to start having line numbers added to my source code examples and Highlight.js does not support this.

It is time for another change. The purpose of this post is demonstrate how to incorporate the PrismJS syntax highlighting tool into Blogger.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Blogger
  • Scrivener 3
  • PrismJS 1.29

Download PrismJS

Visit the PrismJS download page: https://prismjs.com/download.html. On this page you are able to select the languages and plugins you want to include in your prism download. It is tempting to select everything, but, the reality is you will never use some of the languages listed. It only takes a few minutes to go through the language list and select the ones you use most often.

For PrismJS plugins, my primary reason for switching to PrismJS is the Line Numbers plugin. This is an important feature for me. I want to have line numbers added to my source code examples.

Another important plugin is the Autoloader plugin. If you try to style a language you have not previously included in your download, Autoloader will automatically get the styling for that language for you. This is good for occasional use. I would not rely on it all the time. If you start blogging about a new language regularly, re-download PrismJS with that language selected.

What is also nice about the PrismJS download page is that while you are selecting languages and plugins, the URL in your browser is automatically updated to reflect your selections. This means, once you are done selecting all the options you want, save the URL in your your favorite note-taking software (OneNote). Then all you need to do is click on the URL and you don’t have to go through selecting all your languages and plugins again. Very nice!

These are my selections: https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+http+java+javadoc+javadoclike+json+json5+plsql+python+regex+sql+typescript+yaml&plugins=line-numbers+autoloader

Host Your PrismJS Download on OneDrive

After you have downloaded the Prism JS and CSS files, the next thing you need to figure out is what to do with them. There are a couple options:

  1. Cut and paste the contents inside your Blogger theme.
  2. Host the JS and CSS files somewhere and update your Blogger template to use them.

Although option #2 is a bit more complicated, it is the better long-term option in my opinion. Blogger does not allow file uploads, so the files have to be hosted somewhere else. There are a number of different options where to host the files, but I chose to use my Microsoft OneDrive account to do this. I chose OneDrive because I already have an account, I use it all the time, and it is easy to use. Most online file upload system (Google Drive, etc.) allow you to get a read-only, permanent link to a file. That is exactly what we are going to to do.

I’m assuming you already know how to save a file on OneDrive, so I will start from there. Login to OneDrive with a web browser and navigate to the folder where you have the Prism JS and CSS files. As seen in Figure 1, you will need to click three times to generate the embedded code.

  1. Select one of the files.
  2. Click the “Embed” option.
  3. Click the “Generate” button.

Figure 1 - Three Clicks to Generate Embedded Code

Three Clicks to Generate Embedded Code
Three Clicks to Generate Embedded Code

Figure 2 shows an embedded code example. You will notice it is an <iframe> tag with a src attribute (and a few others). We will be concentrating on the src attribute.

Figure 2 - The iframe Embedded Code

The iframe Embedded Code
The iframe Embedded Code

Let us take a look at the <iframe> tag a little more closely:

<iframe src=“https://onedrive.live.com/embed?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127125&authkey=ADxgzT72UZ6zQQM” width=“98” height=“120” frameborder=“0” scrolling=“no”></iframe>

Extract the bolded URL like this:

https://onedrive.live.com/embed?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127125&authkey=ADxgzT72UZ6zQQM

Then changed embed to download like this:

https://onedrive.live.com/download?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127125&authkey=ADxgzT72UZ6zQQM

You will want to do this for both the JS file and the CSS file. When you are done you will have two URL values that look like this.

JS. https://onedrive.live.com/download?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127124&authkey=AIhs3YZuWx_nl8k

CSS. https://onedrive.live.com/download?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127125&authkey=ADxgzT72UZ6zQQM

These URL values are the direct links to your JS file and the CSS file. Test them by pasting the URL values into a browser. The browser should download the file without redirecting to OneDrive. If it does not download directly, something is not right and you should try again.

Now that we have the direct links to the hosted JS and CSS files, let us look at how we update the Blogger theme.

Blogger Theme Updates

Now that the Prism JS and CSS files are hosted on OneDrive and I have permanent URL values to retrieve them, I now need to update my Blogger theme to use these files. I will need to make two updates to the Blogger theme:

  1. Include both the JS and CSS files.
  2. Add the ‘line-numbers’ class to the <body> tag.

Let us take a look at how to do both.

Include both the JS and CSS files

The JS file gets included with a <script> tag and the CS file gets included with a <link> tag. Start by creating both of these tags and drop in the permanent URL values like this:

JS. <script src=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127124&authkey=AIhs3YZuWx_nl8k’ type=‘text/javascript’/>

CSS. <link href=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&resid=C5144D8101C068D%2127125&authkey=ADxgzT72UZ6zQQM’ rel=‘stylesheet’/>

However, your not done yet! Normally this is all you need to do, but Blogger themes have a bit of a quirk. They seem to be saved as XML so the & characters in the URL values are a problem. To successfully save these tags to the Blogger theme, you need to escape the & characters with &amp; like this:

JS. <script src=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127124&amp;authkey=AIhs3YZuWx_nl8k’ type=‘text/javascript’/>

CSS. <link href=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127125&amp;authkey=ADxgzT72UZ6zQQM’ rel=‘stylesheet’/>

These tags are now ready to be used in the Blogger theme.

Add the ‘line-numbers’ class to the <body> tag

Recall that one of the reasons I am switching to Prism is because it was important to me to have line numbers added to my source code examples. This is done by the Prism Line Numbers plugin. To use this plugin, you need to do is add the ‘line-numbers’ class to the <body> tag within the Blogger theme. It looks like this:

<body expr:class=‘&quot;loading line-numbers&quot; + data:blog.mobileClass’>

Now let us get these updates into the Blogger theme.

Updating the Blogger Theme

After you log into your blog, perform the following steps as shown in Figures 3 and 4:

  1. Click “Theme” on the left
  2. Click the down-pointing arrow
  3. Select “Edit HTML”

Figure 3 - Blogger Theme Customization

Blogger Theme Customization
Blogger Theme Customization

Figure 4 - Blogger Edit HTML

Blogger Edit HTML
Blogger Edit HTML

Your are now looking at the HTML template of your blog’s theme. The Prism <script> and <link> tags you created above need to go somewhere within the opening and closing <head></head> tags so it looks like this:

<head>

<script src=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127124&amp;authkey=AIhs3YZuWx_nl8k’ type=‘text/javascript’/> <link href=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127125&amp;authkey=ADxgzT72UZ6zQQM’ rel=‘stylesheet’/>

</head>

The update to <body> is even easier. Just search the template for “<body” and update it to include the “line-numbers” class.

NOTE An HTML element can have multiple class values. The values are separated by a blank space. So note in the example below the blank space between loading and line-numbers.

<body expr:class=‘&quot;loading line-numbers&quot; + data:blog.mobileClass’>

That’s it! Save the file and you are good to go!

Examples

Let us take a look at a few source code syntax highlighting examples to make sure everything is working OK.

Listing 1 - Java

package org.prism.example;

public static final void main(String [] args) {
    System.out.println("Hello world!");
}

Listing 2 - JavaScript

const baseValue = prompt('Enter the base of a triangle: ');
const heightValue = prompt('Enter the height of a triangle: ');

// calculate the area
const areaValue = (baseValue * heightValue) / 2;

console.log(
  `The area of the triangle is ${areaValue}`
);

Listing 3 - TypeScript

class Employee {
    id: number;
    firstName: string;
    lastName: string;

    constructor(id: number, firstName: string, lastName: string) 
    {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + ' ' + this.lastName;
    }
}

// create Employee class object
let employee = new Employee(100, 'Rita', 'Red');
console.log(employee);
console.log(employee.getFullName());

Listing 4 - PL/SQL

DECLARE
  name VARCHAR2(50);
BEGIN
  name := 'Rita';
  DBMS_OUTPUT.PUT_LINE('Hello, ' || name);
END;


FOR i IN 1..10 LOOP
  DBMS_OUTPUT.PUT_LINE('i = ' || i);
END LOOP;

Listing 5 - XML

<Catalog>
	<CD>
		<Title>Empire Burlesque</Title>
		<Artist>Bob Dylan</Artist>
		<Country>USA</Country>
		<Company>Columbia</Company>
		<Price>10.90</Price>
		<Year>1985</Year>
	</CD>
	<CD>
		<Title>Greatest Hits</Title>
		<Artist>Dolly Parton</Artist>
		<Country>USA</Country>
		<Company>RCA</Company>
		<Price>9.90</Price>
		<Year>1982</Year>
	</CD>
</Catalog>

Listing 6 - HTML

<!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>

Listing 7 - JSON

{
  "colors": [
    {
      "color": "red",
      "category": "hue",
      "type": "primary",
      "code": {
        "rgba": [255,0,0,1],
        "hex": "#FF0"
      }
    },
    {
      "color": "blue",
      "category": "hue",
      "type": "primary",
      "code": {
        "rgba": [0,0,255,1],
        "hex": "#00F"
      }
    },
    {
      "color": "yellow",
      "category": "hue",
      "type": "primary",
      "code": {
        "rgba": [255,255,0,1],
        "hex": "#FF0"
      }
    },
    {
      "color": "green",
      "category": "hue",
      "type": "secondary",
      "code": {
        "rgba": [0,255,0,1],
        "hex": "#0F0"
      }
    }
  ]
}

Summary

PrismJS is a nice syntax highlighter for source code examples. Using it with Blogger is a little work, but not too complicated.

Visit the PrismJS download page: https://prismjs.com/download.html and download what you will use most often.

Host the downloaded JS and CSS files on the technology of your choice. My example used OneDrive. You can also use Google Drive, GitLab, AWS, Azure, and I’m sure there are others.

Include the JS and CSS files in the Blogger theme by updating the template:

<head>

<script src=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127124&amp;authkey=AIhs3YZuWx_nl8k’ type=‘text/javascript’/> <link href=‘https://onedrive.live.com/download?cid=0C5144D8101C068D&amp;resid=C5144D8101C068D%2127125&amp;authkey=ADxgzT72UZ6zQQM’ rel=‘stylesheet’/>

</head>

Add the “line-numbers” class to the <body> tag to support the Line Numbers plugin.

<body expr:class=‘&quot;loading line-numbers&quot; + data:blog.mobileClass’>

Save the template change, create a blog with source code examples, and that’s it!

Enjoy!

February 02, 2023

Creating, Signing, and Verifying JWT in Java

Abstract

You use JWTs don’t you? Everyone does, right? But do you know how to generate, sign, and verify them? The purpose of this post is to demonstrate how to code all these operations.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Java 11
  • Maven 3.8.6 (Bundled with NetBeans)

Download

Visit my GitHub page https://github.com/mjremijan to see all of my open source projects. The code for this post is located at: https://github.com/mjremijan/thoth-jwt

Introduction

A JWT is a simple three-part string of encoded characters - header, payload, signature - separated by 2 “.” characters.

xxxxx.yyyyy.zzzzz

JWT technology has been around for years. Read all about the JWT specification on the Introduction to JSON Web Tokens at https://jwt.io/introduction. This blog focuses on the Java code to create and verify JWT values. There are 2 examples:

  1. JWT with Symmetric HMAC SHA256 Signature
  2. JWT with Asymmetric RSA SHA256 Signature

Let’s take a look at them.

JWT with Symmetric HMAC SHA256 Signature

Listing 1 shows the code and Listing 2 shows example output.

Listing 1 - JWT with Symmetric HMAC SHA256 Signature

1. package org.thoth.jwt.main;
2. 
3. import java.util.Base64;
4. import javax.crypto.Mac;
5. import javax.crypto.spec.SecretKeySpec;
6. 
7. /**
8.  *
9.  * @author Michael Remijan mjremijan@yahoo.com @mjremijan
10.  */
11. public class SignatureWithSymmetricalHmacSha256Main 
12. {
13.     public static void main(String[] args) throws Exception 
14.     {
15.         // JWT HEADER
16.         //
17.         // This is the xxxxx of a JWT xxxxx.yyyyy.zzzzz
18.         //
19.         // Given the following JSON document, encode it
20.         // using Java as defined in the JWT specifications
21.         String header = "{\"alg\":\"HS256\",\"typ\": \"JWT\"}";
22.         String headerEncoded 
23.             = Base64.getUrlEncoder()
24.                     .withoutPadding()
25.                     .encodeToString(
26.                         header.getBytes()
27.                     );
28.         String headerDecoded
29.                 = new String(
30.                     Base64.getUrlDecoder().decode(headerEncoded)
31.                 );
32.         
33.         System.out.printf("Header Plain   : %s%n", header);
34.         System.out.printf("Header Encoded : %s%n", headerEncoded);
35.         System.out.printf("Header Decoded : %s%n", headerDecoded);
36.         
37.         
38.         // JWT PAYLOAD
39.         //
40.         // This is the yyyyy of a JWT xxxxx.yyyyy.zzzzz
41.         //
42.         // Given the following JSON document, encode it
43.         // using Java as defined in the JWT specifications
44.         String payload = "{\"sub\":\"TMJR00001\",\"name\":\"Michael J. Remijan\",\"exp\":61475608800,\"iss\":\"info@wstutorial.com\",\"groups\":[\"user\",\"admin\"]}";
45.         String payloadEncoded 
46.             = Base64.getUrlEncoder()
47.                     .withoutPadding()
48.                     .encodeToString(
49.                         payload.getBytes()
50.                     );
51.         
52.         String payloadDecoded
53.                 = new String(
54.                     Base64.getUrlDecoder().decode(payloadEncoded)
55.                 );
56.         
57.         System.out.printf("%n");
58.         System.out.printf("Payload Plain   : %s%n", payload);
59.         System.out.printf("Payload Encoded : %s%n", payloadEncoded);
60.         System.out.printf("Payload Decoded : %s%n", payloadDecoded);
61.         
62.     
63.         // SIGNATURE / VERIFY
64.         // This is the zzzzz of a JWT xxxxx.yyyyy.zzzzz
65.         //
66.         // Hash-based message authentication code(HMAC)
67.         // is a specific type of message authentication code 
68.         // (MAC) involving a cryptographic hash function and 
69.         // a secret cryptographic key. As with any MAC, it 
70.         // may be used to simultaneously verify both the data
71.         // integrity and authenticity of a message.
72.         // 
73.         // A cryptographic hash function (CHF) is any function 
74.         // that can be used to map data of arbitrary size to 
75.         // a fixed-size number of n bits that has special 
76.         // properties desirable for a cryptographic application.
77.         //
78.         // For this example, the process will use the SHA256
79.         // cryptographic hash function and a secret key
80.         // to generate a signatureCreatedFromThisData (hash) of the JWT data.
81.         // This signatureCreatedFromThisData can then be used to verify the
82.         // JWT data has not been tampered.
83.         //
84.         // Typically the secret key is only available on the 
85.         // Authentication Server. The key is used to create the 
86.         // signatureCreatedFromThisData for the JWT. Clients will typically make 
87.         // an authentication request (HTTPS) to the Authentication
88.         // server to verify a JWT. Clients cannot verify a JWT 
89.         // themselves because they do not have access to the
90.         // secret key. However, if a Client is 100% trusted,
91.         // The secret key can be shared with the Client so
92.         // that the Client can do its own verification. 
93.         // WARNING: This means the Client will also be able 
94.         // to make new JWTs, which can be dangerous.
95.         String algorithm  = "HmacSHA256";
96.         String secret = "thisismysupersecretkeywhichshouldonlybeontheauthenticationserver";
97.         SecretKeySpec key = new SecretKeySpec(secret.getBytes(), algorithm);
98.         Mac mac = Mac.getInstance(algorithm);
99.         mac.init(key);
100.         String signatureCreatedFromThisData 
101.             = headerEncoded + "." + payloadEncoded;
102.         String signatureEncoded 
103.             = Base64.getUrlEncoder()
104.                     .withoutPadding()
105.                     .encodeToString(mac.doFinal(
106.                             signatureCreatedFromThisData.getBytes()
107.                         )
108.                     );
109.         
110.         System.out.printf("%n");
111.         System.out.printf("Signature Algorithm : %s%n", algorithm);
112.         System.out.printf("Signature Secret    : %s%n", secret);
113.         System.out.printf("Signaure Encoded    :%s%n", signatureEncoded);
114.     }
115. }
116. 

Listing 2 - HMAC Example Output

Header Plain   : {"alg":"HS256","typ": "JWT"}
Header Encoded : eyJhbGciOiJIUzI1NiIsInR5cCI6ICJKV1QifQ
Header Decoded : {"alg":"HS256","typ": "JWT"}

Payload Plain   : {"sub":"TMJR00001","name":"Michael J. Remijan","exp":61475608800,"iss":"info@wstutorial.com","groups":["user","admin"]}
Payload Encoded : eyJzdWIiOiJUTUpSMDAwMDEiLCJuYW1lIjoiTWljaGFlbCBKLiBSZW1pamFuIiwiZXhwIjo2MTQ3NTYwODgwMCwiaXNzIjoiaW5mb0B3c3R1dG9yaWFsLmNvbSIsImdyb3VwcyI6WyJ1c2VyIiwiYWRtaW4iXX0
Payload Decoded : {"sub":"TMJR00001","name":"Michael J. Remijan","exp":61475608800,"iss":"info@wstutorial.com","groups":["user","admin"]}

Signature Algorithm : HmacSHA256
Signature Secret    : thisismysupersecretkeywhichshouldonlybeontheauthenticationserver
Signaure Encoded    :Xi6kVafrGX18FQIkNZuVJVBbmGbmEzI8cM-5G02S32A

Line #21 of Listing 1 starts the creation of the JWT header. This is the xxxxx part of a xxxxx.yyyyy.zzzzz JWT. As you can see, the code is simple. Use Base64.getUrlEncoder().withoutPadding() for encoding and Base64.getUrlDecoder() for decoding.

NOTE Make sure to use the **.withoutPadding()** encoder. If not, trailing “=” characters will be added by the encoder to make the encoded string the necessary length. These trailing “=” are not allowed by the JWT specification so if you have them, other JWT decoders won’t be able to decode your JWT properly.

Line #44 of Listing 1 starts the creation of the JWT payload, typically user information, but in theory can be anything. This is the yyyyy part of a xxxxx.yyyyy.zzzzz JWT. As you can see, the code is simple. Use Base64.getUrlEncoder().withoutPadding() for encoding and Base64.getUrlDecoder() for decoding. See NOTE above about using the .withoutPadding() encoder.

Line #95 of Listing 1 starts the creation of the JWT signature. This is the zzzzz part of a xxxxx.yyyyy.zzzzz JWT. Listing 1 is an example of using the "alg":"HS256" aka HmacSHA256 algorithm. This is a single-key, symmetric algorithm which relies on a user-generated secret value as seen on line #96. This secret typically is stored outside the application in some kind of configuration system (file, git, database, etc.). Staring with line #102, you see how the MAC is used to finish the hash and the Base64.getUrlEncoder().withoutPadding() is used to encode the hash.

You’ll notice that after signing, there is no more code in Listing 1. Where’s the code showing how to verify a JWT? Well with a single-key, symmetric algorithm like HmacSHA256, the signing and verifying steps are exactly the same. To verify, the signature needs to be generated again and compared with the zzzzz part of a xxxxx.yyyyy.zzzzz JWT.

That’s it for JWT with Symmetric HMAC SHA256 Signature.

JWT with Asymmetric RSA SHA256 Signature

Listing 3 shows the code and Listing 4 shows example output.

Listing 3 - JWT with Asymmetric RSA SHA256 Signature

1. package org.thoth.jwt.main;
2. 
3. import java.security.KeyPair;
4. import java.security.KeyPairGenerator;
5. import java.security.PrivateKey;
6. import java.security.PublicKey;
7. import java.security.Signature;
8. import java.util.Base64;
9. 
10. /**
11.  *
12.  * @author Michael Remijan mjremijan@yahoo.com @mjremijan
13.  */
14. public class SignatureWithAsymmetricalRsaSha256Main 
15. {
16.     public static void main(String[] args) throws Exception 
17.     {
18.         // JWT HEADER
19.         //
20.         // This is the xxxxx of a JWT xxxxx.yyyyy.zzzzz
21.         //
22.         // Given the following JSON document, encode it
23.         // using Java as defined in the JWT specifications
24.         String header = "{\"alg\":\"RS256\",\"typ\": \"JWT\"}";
25.         String headerEncoded 
26.             = Base64.getUrlEncoder()
27.                     .withoutPadding()
28.                     .encodeToString(
29.                         header.getBytes()
30.                     );
31.         String headerDecoded
32.                 = new String(
33.                     Base64.getUrlDecoder().decode(headerEncoded)
34.                 );
35.         
36.         System.out.printf("Header Plain   : %s%n", header);
37.         System.out.printf("Header Encoded : %s%n", headerEncoded);
38.         System.out.printf("Header Decoded : %s%n", headerDecoded);
39.         
40.         
41.         // JWT PAYLOAD
42.         //
43.         // This is the yyyyy of a JWT xxxxx.yyyyy.zzzzz
44.         //
45.         // Given the following JSON document, encode it
46.         // using Java as defined in the JWT specifications
47.         String payload = "{\"sub\":\"TMJR00001\",\"name\":\"Michael J. Remijan\",\"exp\":61475608800,\"iss\":\"info@wstutorial.com\",\"groups\":[\"user\",\"admin\"]}";
48.         String payloadEncoded 
49.             = Base64.getUrlEncoder()
50.                     .withoutPadding()
51.                     .encodeToString(
52.                         payload.getBytes()
53.                     );
54.         
55.         String payloadDecoded
56.                 = new String(
57.                     Base64.getUrlDecoder().decode(payloadEncoded)
58.                 );
59.         
60.         System.out.printf("%n");
61.         System.out.printf("Payload Plain   : %s%n", payload);
62.         System.out.printf("Payload Encoded : %s%n", payloadEncoded);
63.         System.out.printf("Payload Decoded : %s%n", payloadDecoded);
64.         
65.     
66.         // SIGNATURE
67.         //
68.         // This is the zzzzz of a JWT xxxxx.yyyyy.zzzzz
69.         //
70.         // RSA (Rivest--Shamir--Adleman) is a public-key cryptosystem 
71.         // that is widely used for secure data transmission.
72.         // In a public-key cryptosystem, the public key is used for
73.         // encryption and the private key is used for decryption. The
74.         // private key is also used for creating digital signatures
75.         // of data and the public key is used for verifying the
76.         // digital signature.
77.         //
78.         // A cryptographic hash function (CHF) is any function 
79.         // that can be used to map data of arbitrary size to 
80.         // a fixed-size number of n bits that has special 
81.         // properties desirable for a cryptographic application.
82.         //
83.         // For this example, the process will use the SHA256
84.         // cryptographic hash function along with a public/private
85.         // keypair and the RSA encryption algorithm to generate
86.         // a signature for the JWT.
87.         //
88.         // The private key is used for creating the signature.
89.         //
90.         KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
91.         keyGenerator.initialize(1024);
92.         KeyPair kp = keyGenerator.genKeyPair();
93.         PublicKey publicKey = (PublicKey) kp.getPublic();
94.         PrivateKey privateKey = (PrivateKey) kp.getPrivate();
95.         String algorithm = "SHA256withRSA";
96.         String signatureCreatedFromThisData 
97.             = headerEncoded + "." + payloadEncoded;
98.         
99.         Signature privateSignature 
100.             = Signature.getInstance(algorithm);
101.         privateSignature.initSign(privateKey);
102.         
103.         System.out.printf("%n");
104.         System.out.printf("Algorithm    : %s%n", algorithm);
105.         System.out.printf("Public Key   : %s%n", Base64.getEncoder().encodeToString(publicKey.getEncoded()));
106.         System.out.printf("Private Key  : %s%n", Base64.getEncoder().encodeToString(privateKey.getEncoded()));
107.         
108.         privateSignature.update(signatureCreatedFromThisData.getBytes());
109.         String signatureEncoded 
110.                 = Base64.getUrlEncoder()
111.                         .withoutPadding()
112.                         .encodeToString(
113.                             privateSignature.sign()
114.                         );
115.         System.out.printf("%n");
116.         System.out.printf("Signaure Encoded         : %s%n", signatureEncoded);
117.         
118.         // VERIFY
119.         // This is the zzzzz of a JWT xxxxx.yyyyy.zzzzz
120.         //
121.         // The public key is used for verifying the signature.
122.         //
123.         // Becuase the public key is used for creating a signature,
124.         // it safe to distribute the public key to Clients so 
125.         // that Clients can verify the JWT signature without
126.         // having to ask the Authentication Server for verification
127.         //
128.         
129.         Signature publicSignature = Signature.getInstance(algorithm);
130.         publicSignature.initVerify(publicKey);
131.         publicSignature.update(signatureCreatedFromThisData.getBytes());
132.         boolean verified = publicSignature.verify(
133.             Base64.getUrlDecoder().decode(signatureEncoded)
134.         );
135.         System.out.printf("Signature Verified (t/f) : %b%n", verified);
136.     }
137. }
138. 

Listing 4 - RSA Example Output

Header Plain   : {"alg":"RS256","typ": "JWT"}
Header Encoded : eyJhbGciOiJSUzI1NiIsInR5cCI6ICJKV1QifQ
Header Decoded : {"alg":"RS256","typ": "JWT"}

Payload Plain   : {"sub":"TMJR00001","name":"Michael J. Remijan","exp":61475608800,"iss":"info@wstutorial.com","groups":["user","admin"]}
Payload Encoded : eyJzdWIiOiJUTUpSMDAwMDEiLCJuYW1lIjoiTWljaGFlbCBKLiBSZW1pamFuIiwiZXhwIjo2MTQ3NTYwODgwMCwiaXNzIjoiaW5mb0B3c3R1dG9yaWFsLmNvbSIsImdyb3VwcyI6WyJ1c2VyIiwiYWRtaW4iXX0
Payload Decoded : {"sub":"TMJR00001","name":"Michael J. Remijan","exp":61475608800,"iss":"info@wstutorial.com","groups":["user","admin"]}

Algorithm    : SHA256withRSA
Public Key   : MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRxw6Ncvsx0/kDYKwA6pLwn3hSbRdYFBOv1aiBomF7lPfOPfqaTgN2yPN6hErlLAP2d+94ig4uXv7MROXlsn8n7jdr2g5yo/kC92RJwALpffzBlWh29hEadiznWp2u0b0h++Cn4HJejfJpZOek6wurBL/7K2Y2TELOg8eg1uipEwIDAQAB
Private Key  : MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANHHDo1y+zHT+QNgrADqkvCfeFJtF1gUE6/VqIGiYXuU9849+ppOA3bI83qESuUsA/Z373iKDi5e/sxE5eWyfyfuN2vaDnKj+QL3ZEnAAul9/MGVaHb2ERp2LOdana7RvSH74Kfgcl6N8mlk56TrC6sEv/srZjZMQs6Dx6DW6KkTAgMBAAECgYBqVyPzZGQeADxtD+ZhmIfgXpaaAh8hURwhuIdxH6WXBg8Qh66v5fgvkPKMGt/0iHmByY6lZiaGLzWuywZXiEKYSl6tpK8WtiY+gyYxOVgFckAKzjBJ4GYb6YvPI5p5/qDFqN/9Ca4vDn9URFEIRSBIc1it8TWzze8x2Ljd4vu54QJBAOmlSJ/m4dHJMzLnyM6Y1x/e2fqm48DbfV3m+jDjyR7YrTwcVoZSC17B1z4J7W+/Ea7N61UWRRvelvC4c8OKkEkCQQDl2StC7vbKCsnDAFyDjUADq7p2aE+vVH7v7ZUjHhsTXMF8TFMgfkxl5cH58nDNq1Yo82SKGvMeRnmBYHeHlqZ7AkBP1Ur4YBJ+9QmKdkpV1UGEQUgn7ghaKGUwxbBtLhfVc2HV7TTfVn9OFFuwdgHsMdQf73peq2pXuHnIrK3ZfaoJAkEAh0nXg/NCAdRtw8C/s5L9feujujRVyt6SRMj0ApKi3ze2j2Ihf7u3XjbpgSRprzVNZpc0s3F/bm+O708HrCBJZwJBANPeVhBizgqPZOiQxLRxpNN2+EvEfs8js7YFRwB45orM/+9yVelNojEKxcHT7zS6j59dTlwvbGp6LVrKCrwtwLw=

Signaure Encoded         : HO4FLrLDt4ObECVWRiUGIGUimU1M70Y9aILT5op0UkV-kbEx8AqjCsLTh-Y1zOAisvFmuH5LYRw1wQyncQ5uEUWJYcoeldr-1_uFlpD2LqUy-QZfng8e6pxXOopL8Of_OcNEOqRijmI_dob8Gf0UnT7GQWpGTl32cIuuIFDeRHo
Signature Verified (t/f) : true

Line #24 of Listing 3 starts the creation of the JWT header. This is the xxxxx part of a xxxxx.yyyyy.zzzzz JWT. As you can see, the code is simple. Use Base64.getUrlEncoder().withoutPadding() for encoding and Base64.getUrlDecoder() for decoding.

NOTE Make sure to use the **.withoutPadding()** encoder. If not, trailing “=” characters will be added by the encoder to make the encoded string the necessary length. These trailing “=” are not allowed by the JWT specification so if you have them, other JWT decoders won’t be able to decode your JWT properly.

Line #47 of Listing 3 starts the creation of the JWT payload, typically user information, but in theory can be anything. This is the yyyyy part of a xxxxx.yyyyy.zzzzz JWT. As you can see, the code is simple. Use Base64.getUrlEncoder().withoutPadding() for encoding and Base64.getUrlDecoder() for decoding. See NOTE above about using the .withoutPadding() encoder.

Line #90 of Listing 3 starts the creation of the JWT signature. This is the zzzzz part of a xxxxx.yyyyy.zzzzz JWT. Listing 3 is an example of using the "alg":"RS256" aka SHA256withRSA algorithm. This is a two-key, asymmetric algorithm which relies on a public/private keypair created on Line #92. A Signature object is created on line #99 and it is initialized with the private key. Staring with line #108, see how the Signature is used to create a signature and the Base64.getUrlEncoder().withoutPadding() is used to encode the signature.

NOTE The public/private keypair will need to be generated outside the application and kept in some kind of configuration store (file, git, database, etc.). This is an exercise left up to you.

Line #129 of Listing 3 starts the verify process. A Client may verify a JWT it receives from an Authentication server to guard against tampering while in transit. To verify a JWT created using an asymmetric RSA SHA256 signature, the Client will need the public key. This typically is not a problem since public keys are designed to be giving away. Line #132 demonstrates the call to .verify().

That’s it for JWT with Asymmetric RSA SHA256 Signature.

Summary

Most of this blog is the code. Review the code, top to bottom, it is not overly complicated. But now you know how to create and verify JWT values using both a Symmetric HMAC SHA256 Signature and an Asymmetric RSA SHA256 Signature.

Enjoy!

References

Introduction to JSON Web Tokens. (n.d.). JWT. https://jwt.io/introduction.

Debugger. (n.d.). JWT. https://jwt.io/#debugger-io

Alx. (2017, December). Create jwt in java using Public key rsa. https://wstutorial.com/misc/jwt-java-public-key-rsa.html

Base64 withoutPadding Encoding of string or byte array (Java8). (n.d.). MakeInJava Tutorials. https://makeinjava.com/base64-withoutpadding-encoding-string-byte-array-java8/

Poulsen, Søren. (n.d.). Calculate HMAC-Sha256 with Java. https://sorenpoulsen.com/calculate-hmac-sha256-with-java

Dommerholt, Niels. (2016, December 28). Example of RSA generation, sign, verify, encryption, decryption and keystores in Java. https://gist.github.com/nielsutrecht/855f3bef0cf559d8d23e94e2aecd4ede1

HMAC. (2023, January 1). Wikipedia. https://en.wikipedia.org/wiki/HMAC

Cryptographic hash function. (2023, January 10). Wikipedia. https://en.wikipedia.org/wiki/Cryptographic_hash_function

Hash function. (2023, February 1). Wikipedia. https://en.wikipedia.org/wiki/Hash_function