Comparison guide: OpenAPI/Swagger Java client generation
At Speakeasy, the team specializes in producing idiomatic SDKs in various programming languages, including Java. The approach to SDK generation prioritizes a rich developer experience that enables API providers to concentrate on refining APIs and empowers developer-users to efficiently leverage services.
In this article, we’ll compare creating a Java SDK using Speakeasy to creating one using the OpenAPI Generator
Below is a table that summarizes the key differences between the two SDKs:
Read more about these headline features of Speakeasy-created Java SDKs in the March 2024 release notes, or consult the Speakeasy Java SDK documentation.
For a detailed technical comparison, read on!
Installing the CLIs
For this comparison, we need both the Speakeasy and OpenAPI Generator CLIs installed to generate the Java SDKs from the specification YAML file. We’re using macOS, so we use Homebrew to install the CLIs.
Installing the Speakeasy CLI
Install the Speakeasy CLI by running the following command in the terminal:
You can check the version to ensure installation was successful:
If you encounter any errors, take a look at the Speakeasy SDK creation documentation.
Installing the OpenAPI Generator CLI
Install the OpenAPI Generator CLI by running the following command in the terminal:
You can check the version:
Browse the OpenAPI Generator documentation
Downloading the Swagger Petstore specification
We need an OpenAPI specification YAML file to generate SDKs for. We’ll use the Swagger Petstore specification, which you can find at https://petstore3.swagger.io/api/v3/openapi.yaml
Download the file in and save it as petstore.yaml
with the following command in the terminal:
Validating the specification file
Let’s validate the spec using both the Speakeasy CLI and OpenAPI Generator.
Validation using Speakeasy
Run the following command in the terminal where the specification file is located:
The Speakeasy validator returns the following:
The Speakeasy CLI validation result gives us a handy tool for switching between the errors, warnings, and hints tabs with the option to navigate through the results on each tab.
In this instance, Speakeasy generated ten warnings. Let’s correct them before continuing.
Notice that some of the warnings contain a default
response. For completeness, we’d like to explicitly return a 200
HTTP response. We’ll make the following modifications in the petstore.yaml
file.
When the updatePetWithForm
operation executes successfully, we expect an HTTP 200
response with the updated Pet
object to be returned.
Insert the following after responses
on line 250:
Similarly, following successful createUser
and updateUser
operations, we’d like to return an HTTP 200
response with a User
object.
Add the following text to both operations below responses
:
Now we’ll add the same response to four operations. Copy the following text:
Paste this response after responses
for the following operations:
deletePet
deleteOrder
logoutUser
deleteUser
We are left with three warnings indicating potentially unused or orphaned objects and operations.
For unused objects, locate the following lines of code and delete them:
To remove the unused request bodies, locate the following lines and delete them:
Now if you validate the file with the Speakeasy CLI, you’ll notice there are no warnings:
Validation using OpenAPI Generator
To validate the petstore.yaml
specification file with OpenAPI Generator, run the following command in the terminal:
The OpenAPI Generator returns the following response, indicating no issues detected.
Now that we have made the petstore.yaml
file more complete by fixing the warnings, let’s use it to create SDKs.
Creating SDKs
We’ll create Java SDKs using Speakeasy and OpenAPI Generator and then compare them.
Creating an SDK with Speakeasy
Create a Java SDK from the petstore.yaml
specification file using Speakeasy by running the following command in the terminal:
The generator will return some logging results while the SDK is being created and a success indicator on completion.
Creating an SDK with OpenAPI Generator
Run the following command in the terminal to generate a Java SDK using OpenAPI Generator:
The generator returns various logs and finally a successful generation message.
SDK code compared: Project structure
Let’s compare the two project structures by printing a tree structure of each SDK directory’s src
folder.
Run the following command to get the Speakeasy SDK structure:
The results of the project structure are displayed as follows:
Now run the following command for the OpenAPI Generator SDK folder:
The OpenAPI Generator SDK structure looks like this:
The Speakeasy-created SDK contains more generated files than the SDK from OpenAPI Generator, which is partly due to the Speakeasy SDK being less dependent on third-party libraries.
Model and usage
Let’s take a look at how Speakeasy generates model classes for creating and updating a Pet
object.
The Speakeasy model follows the builder pattern to construct objects with many optional parameters, making the code more readable and easier to use.
Let’s see how the OpenAPI Generator SDK performs the same operation:
The OpenAPI Generator SDK focuses on manual serialization and deserialization using Gson, providing setter methods for individual properties of the Pet
object.
The two SDKs have distinctly different approaches to handling object creation, validation, and JSON serialization, with the Speakeasy-generated SDK emphasizing fluid and declarative object creation using modern patterns and annotations for handling JSON data.
Let’s look more closely at how the Pet
model attributes are declared in each SDK.
Notice how the Speakeasy SDK uses Jackson annotations for the JSON serialization and deserialization of objects.
Compare this to the OpenAPI Generator SDK Pet
model that uses Gson annotations:
Let’s take a moment and identify what the differences are between the Jackson vs GSON libraries and what features each has.
The Gson JSON library is easy to use and implement and well-suited to smaller projects. It provides an API for JSON support but doesn’t support extensive configuration options.
On the other hand, Jackson is designed to be more configurable and flexible when it comes to JSON serialization and deserialization. Jackson is the standard JSON-support library in many popular Java frameworks (like Spring, Jersey, and RESTEasy), it’s widely used in the Java community, and it’s actively supported and frequently updated. Jackson is also generally faster and offers extensive configuration options.
The use of the Jackson library in the Speakeasy-generated SDK provides us with a firm foundation for building fast and scalable applications.
HTTP communication
Java 11 (the minimum version supported by Speakeasy) significantly improved HTTP communication with the java.net.http package providing a powerful HTTPClient
class for enhanced HTTP communication.
Given the OpenAPI Generator SDK is Java 8 compatible, we suspected it might use some third-party libraries. On inspection, our suspicions were confirmed: The SDK uses a third-party library to handle HTTP communication.
Take a look at the following method to add a new Pet
object (from the PetApi.java
file):
The addPet
method in turn calls the addPetWithHttpInfo(pet)
method:
Note how the method uses the okhttp3.Call
object.
We examined the dependencies configured in the build.gradle
file and discovered the okhttp
dependency:
Having established that the OpenAPI Generator SDK uses the OkHttp library, we were curious to see how the Speakeasy-generated SDK handles HTTP communication.
Take a look at this extract from the addPetJson
method in the Pet.java
file of the Speakeasy SDK:
This method uses HTTPClient
, HTTPRequest
, and HTTPResponse
objects. If we look at the import statements, we can see that these objects are generated from the following classes:
The HTTPClient
and HTTPRequest
interfaces are both generated by Speakeasy.
We can see the HTTPClient
interface implemented in SpeakeasyHTTPClient.java
to establish the HTTP communication method:
The Speakeasy SDK uses the Java HTTP APIs that were introduced in Java 11. Some of the benefits of using the built-in Java HTTP APIs are:
- Standardization: By using the HTTP Client API supported in Java 11, the SDK uses the standards provided and supported by modern Java SDK providers. The
HttpClient
class integrates more easily with the other Java APIs in the Java SDK. - Asynchronous support: Asynchronous HTTP communication is not available in Java 8, making it harder to build scalable applications. The HTTP Client API asynchronous HTTP communication available in Java 11 provides a CompletableFuture object immediately after calling the API, which gives developers more control.
- Performance and efficiency: The HTTP Client is created using a builder and allows for configuring client-specific settings, such as the preferred protocol version (HTTP/1.1 or HTTP/2). It also supports Observable APIs.
- Security, stability, and long-term support: As a standard Java API, the HTTP Client is more stable and secure, and benefits from the long-term support cycles of new Java versions.
Retries
The SDK created by Speakeasy can automatically retry requests.
You can enable retries globally or per request using the x-speakeasy-retries
extension in your OpenAPI specification document.
Let’s add the x-speakeasy-retries
extension to the addPet
method in the petstore.yaml
file:
If you re-generate the SDK now, the new retry configuration will be included.
For more information on configuring retries in your SDK, take a look at the retries documentation.
SDK dependencies
Let’s compare dependencies in the two SDKs.
Here are the OpenAPI Generator SDK dependencies in build.gradle
:
Here are the Speakeasy SDK dependencies from build.gradle
:
The OpenAPI Generator SDK implements more libraries than the Speakeasy SDK, possibly due to the compatibility requirements and limitations of Java 8. Depending on fewer third-party implementations provides the Speakeasy SDK with some advantages:
- Less maintenance: Projects with fewer dependencies have a lower maintenance overhead and less versioning to keep track of long term.
- Reduced risk of dependency-related issues: Third-party dependencies increase the risk of bugs and security failures that depend on the third-party provider to fix. A security flaw in a third-party dependency makes your application vulnerable.
- Improved performance: Code generally works better in standard Java APIs as they have been through rigorous testing and QA cycles before being made available to the public.
- Easier adoption: Projects tend to more readily accept SDK builds that rely on fewer third-party dependencies, due to strict policies regarding the use and management of these dependencies.
Handling non-nullable fields
Let’s see how Speakeasy’s enhanced null safety and Optional support work on fields in the Pet
object.
Take a look at the following declaration taken from the Pet
object in the Speakeasy SDK org.openapis.openapi.models.components.Pet.java
file:
Note that the @JsonInclude
annotation indicates it is NON-ABSENT
and the Optional
class is used. The status field here is an enum (Status
) wrapped in the Optional
class.
Let’s examine the Status
enum object:
Let’s compare the Speakeasy SDK status
field declaration to the same field in the OpenAPI Generator SDK. The following declaration is taken from the org.openapitools.client.model.Pet.java
file:
At first glance, the OpenAPI Generator SDK also uses an enum approach, representing the status
field as an enum called StatusEnum
with three possible values: AVAILABLE
, PENDING
, and SOLD
. A lot of code is generated around this field to handle the enum, but the Pet
object does not indicate that the OpenAPI Generator SDK status
field is non-nullable at this point.
In contrast, Speakeasy uses a direct approach to non-nullable fields. The Speakeasy SDK also uses a Status
enum for the status
field, but it is wrapped in the Optional
class provided by the Java standard APIs.
Declaring the status
field as the Status
type wrapped in the Optional
class has some benefits to the developer:
- It helps to avoid possible
NullPointerException
errors when accessing anull
value. - It provides a modern way for developers to identify the absence of a value using the
isPresent()
method from theOptional
class API and exposes other usable methods likeorElse()
andorElseThrow()
. - It clearly states the intent and use of the code, which helps to reduce bugs in the long run.
Let’s see how client validation works by passing a null
value to the findPetsByStatus()
method, which expects Optional<? extends Status> status
. We create the following builder pattern for a new request:
When we execute this bit of code, we get the following exception:
The same exception is generated if we remove the name
field from the builder
declaration of a new Pet
object:
When we execute the above code, we get the exception:
The null check validation generates this exception when the Pet
object is initiated and certain values are null. If we look at the class constructor in our Pet.java
model in the Speakeasy SDK:
We can see that the exception is generated in the Utils.checkNotNull()
method:
Therefore, if we omit the name
field or pass a null
value in the findPetByStatus()
method, an exception is generated by the check null validation because the name
and status
fields explicitly set to null
in this case.
Let’s try creating a Pet
object without a name
field using the OpenAPI Generator SDK:
When we execute the above code, we get a mixed result. The following exception is generated:
It appears that the Pet
object was created on the API, but the call failed retrospectively on the client side. The exception was generated by the SDK’s validation process, which checks the JSON response received from the API. You can see the created object in the JSON response included in the exception:
Validation failed because the name was missing from the JSON string. This validation method is not helpful, as it checks the response after the API call rather than before the request is sent. Consequently, an invalid object was created on the API and the client process failed.
Speakeasy’s proactive client validation and method of handling non-nullable fields with the use of the Optional
class is elegant. Code that is easy to read, understand, and use, and that also helps to build null safety is essential for building robust, maintainable SDKs.
Generated documentation
Both Speakeasy and OpenAPI Generator generate SDK documentation for the generated code.
Each generator creates a README file to help users get started with the SDK. The OpenAPI Generator README outlines the SDK’s compatibility with Java, Maven, and Gradle versions and identifies the available API routes. The Speakeasy README file is more complete and documents more examples.
Speakeasy also generates additional documentation in the docs
directory, including more detailed explanations of the models and operations; examples of creating, updating, and searching objects; error handling; and guidance on handling exceptions specific to the OpenAPI specification file. A handy “Getting Started” section details how to build the SDK.
In general, we found the Speakeasy documentation to be more complete and helpful. We tested many API call examples from the documentation, and conclude that the Speakeasy docs are production-ready.
Supported Java versions
The Speakeasy-generated SDK supports Java 11+ environments, and the SDK generated by OpenAPI Generator supports Java 8+.
While the OpenAPI SDK supports more codebases including those still using Java 8, the Speakeasy SDK leverages the enhancements provided by Java 11. Java 8 was released in March 2014, and was the most widely used version of Java until version 11 was released in September 2019.
In 2023, New Relic reported that Java 11 is used in around 56% of production applications, while Java 8 is still in use at around 33%. Both versions are important long-term support (LTS) versions.
Summary
We’ve seen how easy it is to generate a powerful, idiomatic SDK for Java using Speakeasy.
If you’re building an API that developers rely on and would like to publish full-featured Java SDKs that follow best practices, we highly recommend giving the Speakeasy SDK generator a try.
For more customization options for your SDK using the Speakeasy generator, please see the Speakeasy documentation.
Join our Slack community to let us know how we can improve our Java SDK generator or suggest features.
Last updated on