Amper by JetBrains: Defining Gradle Builds through YAML – JVM Weekly vol. 153

Once again, we have a fully-packed edition – today with fewer news items, but more in-depth content. I hope you enjoy it.

Article cover

1. Serious Section on Serious Topics – New Developments in Cryptography Handling

Let’s start with topics related to security, as last week we received an interesting announcement from Oracle itself.

A mandatory XKCD comic for a light break before we proceed further.

JCA, or Java Cryptography Architecture, is a set of interfaces (introduced in JDK 1.1 in 1997) that enable integration and access to various cryptographic operations, such as encryption, signing, or key generation. Jipher JCE is a solution from Oracle, designed as an implementation of JCA, and it integrates a pre-configured and FIPS-compliant version of OpenSSL 3.0, specially adapted to handle algorithms allowed by FIPS standards. During KubeCon North America 2023 Oracle ogłosiło, Oracle announced that this solution, previously a component of their cloud, will be made available to the community.

Now, a bit about FIPS. It stands for Federal Information Processing Standards, which are publicly announced standards developed by the National Institute of Standards and Technology (NIST) in the United States. These standards are applied in government computer systems (except those related to defense) to ensure their security and interoperability. This includes the aforementioned FIPS module of OpenSSL 3.0.

The key word in the announcement is broadly understood “compliance,” but what sets Jipher JCE apart is also its performance – it has been built based on Project Panama, which gives it an advantage over older competition like Bouncy Castle… supposedly, as so far, we have only received an announcement that solution will be merged into OpenJDK.

However, that’s not all. Oracle announced its intention to increase its involvement in the Cloud Native Computing Foundation (CNCF). This commitment includes $3 million in credits for infrastructure as part of Ampere Arm’s computing power in Oracle Cloud Infrastructure. All the announcements can be found here.

Speaking of security, back in August, the Java Dilithium library had its debut. It is a “hobbyist” implementation of the C-based Dilithium library. Dilithium, part of the CRYSTALS algorithm suite, has been recommended by the previously mentioned NIST as a primary algorithm for post-quantum cryptography. It is based on algebraic lattices, offering several solutions with varying levels of security and supporting deterministic signature schemes. For those interested in cryptography, the main substance can be found in this class.

Yes, my daughter is helping me with research for this edition.

Although this implementation, designed for the author’s satisfaction and not intended for production use, passes all available tests and includes features like serialization and deserialization. It is, however, a project created “for fun”, yet it’s worth examining as it illustrates the trend in the evolution of cryptographic standards and the ongoing search for algorithms in the face of advancements in quantum computing.

Let’s remember not to fall into tunnel vision while working on such projects.
Discover more IT content selected for you
In Vived, you will find articles handpicked by devs. Download the app and read the good stuff!

phone newsletter image

2. Amper – Gradle defined using YAML

Programmers’ habits are changing – in recent years (now probably a decade), we’ve seen a surge of CI/CD solutions allowing easy definition of various process steps, declaratively configured using YAML files – just to mention GitHub Actions or TravisCI. When you think about it, there isn’t a huge conceptual difference between build scripts (especially simpler ones) and Continuous Integration pipelines. The trend of “yamlization” hasn’t strongly penetrated the world of build tools, at least not in the broad Java ecosystem. We do have declarative Maven with its less readable XML, and its focus on “project management” (POM is, after all, Project Object Model), but its lack of flexibility led many developers to look towards the more extendable Gradle. This extendability, however, often leads to overly complicated scripts that are easy to get lost in.

An endless cycle that we seem unable to break free from.

This is particularly painful for JetBrains, whose implementation of Kotlin Multiplatform has starkly highlighted the complexity of Gradle with its heavily imperative approach. Maintaining applications across several platforms, developers often have to spend a lot of time due to continuous changes in modules, dependencies, and the need for cross-platform compatibility. To address these challenges, JetBrains, in collaboration with Gradle, initiated an experimental project named Amper. This tool aims to simplify project configuration and enhance user experiences in IDE environments, especially for those working with Java and Kotlin. Implemented as a Gradle plugin, Amper uses the YAML format for project configurations. The setup looks like this:

  type: lib
  platforms: [jvm, android, iosArm64, iosSimulatorArm64, iosX64]

# Shared Compose dependencies:
  - org.jetbrains.compose.foundation:foundation:1.5.0-rc01: exported
  - org.jetbrains.compose.material3:material3:1.5.0-rc01: exported

# Android-only dependencies  
  # integration compose with activities
  - androidx.activity:activity-compose:1.7.2: exported
  - androidx.appcompat:appcompat:1.6.1: exported

# iOS-only dependencies with a dependency on a CocoaPod
  - pod: 'FirebaseCore'
    version: '~> 6.6'

  # Enable Kotlin serialization
    serialization: json
  # Enable Compose Multiplatform framework
  compose: enabled

No one is even trying to hide their source of inspiration here.

Although currently it only supports Kotlin and Kotlin Multiplatform, Amper also promises future support for Java and Swift.

By adding a declarative configuration layer based on YAML over Gradle, Amper offers a simpler and potentially less error-prone approach to project configuration. This initiative aims to make Gradle more accessible and user-friendly, especially for developers who might be overwhelmed by its complexity.

I must honestly admit that I have mixed feelings about this solution. On one hand, I see a clear need to simplify the process of defining builds in Gradle, similar to Maven but with more intuitive management of dependencies and plugins. Using a declarative syntax akin to that used in popular CI tools like GitHub Actions seems like a positive step. However, I believe we should approach this cautiously. There’s a risk that simplification might limit the system’s ability to handle less standard requirements – which was precisely why so many people started migrating from Maven. Overall, I’m cautiously optimistic about the potential benefits of Amper, but I hope that its adoption won’t lead to the loss of the flexibility that characterizes Gradle.

But why does it have to be YAML again?

3. Do You Know What Invoke Dynamic Is and How It Works?

Too much news can be overwhelming, right? That’s why today I have a “back to basics” for you – a great article about one of the more intriguing parts of the JVM, presented in my favorite, accessible way.

Invoke dynamic, commonly abbreviated as indy, is a bytecode-level instruction introduced in Java 7. Its primary goal is to facilitate the implementation of dynamically typed languages (like Python or Ruby), alongside statically typed languages (such as Java) on the JVM. Essentially, this instruction provides a flexible and efficient way to handle method calls in scenarios where the method type is not known until runtime.

But of course, there are many nuances associated with it, which is why today I wanted to share with you the article The Hidden Dynamic Life of Java by Natalia Dziubenko. The text provides a clear understanding of the differences between statically and dynamically typed languages and how these differences affect the functionality of the JVM itself. It then discusses various method invocation instructions in the JVM, such as invokevirtual and invokestatic, and how invokedynamic differs from them. Moreover, the article offers practical, easier-to-understand examples of using invokedynamic in Java, such as for string concatenation, Pattern Matching, or lambdas. The piece also touches on the challenges associated with dynamic behavior in Ahead-Of-Time (AOT) compilation and how invokedynamic fits into this landscape, especially in technologies like GraalVM.

Generally, Natalia’s Medium is a little “hidden gem” that I discovered this week, and I’m not sure how it managed to stay hidden from me until now, as her articles offer a rich overview of less-known aspects of Java. I’m certain that her Medium will be an excellent resource for anyone wanting to deepen their knowledge of the JVM. For me, it was an instant follow 😃

And I love the charming style of the illustrations.
Discover more IT content selected for you
In Vived, you will find articles handpicked by devs. Download the app and read the good stuff!

phone newsletter image

4. Finally, a philosophical take on exceptions and type theory.

The general attitude of the programming community towards Java’s *Checked Exceptions* is (at best) mixed – a significant portion of programmers find them burdensome and limiting. They require methods to declare the exceptions that may occur within them, and those calling these methods must handle these exceptions or enforce their handling downstream. This aspect of Java makes sense on paper (after all, it’s good to know what could go wrong), but it is often perceived as overly verbose and can lead to complicated code, especially in cases where catching or propagating many different exceptions is necessary.

Of course, there are also simpler ways to handle this.

The article Why Checked Exceptions Failed by Fernando Borretti provides a thoughtful critique of Checked Exceptions in Java, questioning their practicality and integration with the rest of the language’s syntax. It points out that although Java added these additional details to method signatures, it didn’t fully integrate this concept with other language features, leading to a lack of what the author refers to as “exception throwing polymorphism.”

The article is worth reading as it explores the deeper implications of Java’s design decisions regarding exceptions. It explains the reasons behind the practical limitations imposed by checked exceptions, such as difficulties in using them alongside interfaces and generic types. It contrasts this with the approach of functional languages, which use types like Option and Result to handle errors. The author also argues why this approach more naturally fits into the existing type systems of these languages.

Furthermore, the article serves as a reminder of how complex the problem of programming language design is. It illustrates how adding or modifying a single piece of syntax can have wide implications, requiring careful consideration and integration with the entire language.

Twisting the knife in the wound™️