# https://opencollective.com/openapi_generator/donate                          #
################################################################################
```

## 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:

```bash
cd petstore-sdk-java-speakeasy/src/main/java
tree
```

The results of the project structure are displayed as follows:

```bash
||____org
| |____openapis
| | |____openapi
| | | |____Pet.java
| | | |____SecuritySource.java
| | | |____User.java
| | | |____utils
| | | | |____SpeakeasyMetadata.java
| | | | |____SecurityMetadata.java
| | | | |____LazySingletonValue.java
| | | | |____RetryConfig.java
| | | | |____TypedObject.java
| | | | |____BigDecimalString.java
| | | | |____Response.java
| | | | |____OneOfDeserializer.java
| | | | |____MultipartFormMetadata.java
| | | | |____JSON.java
| | | | |____Hooks.java
| | | | |____Deserializers.java
| | | | |____QueryParameters.java
| | | | |____Utils.java
| | | | |____QueryParamsMetadata.java
| | | | |____Retries.java
| | | | |____RequestBody.java
| | | | |____RequestMetadata.java
| | | | |____Security.java
| | | | |____Metadata.java
| | | | |____SpeakeasyHTTPClient.java
| | | | |____BackoffStrategy.java
| | | | |____SerializedBody.java
| | | | |____Types.java
| | | | |____HTTPClient.java
| | | | |____Options.java
| | | | |____HeaderMetadata.java
| | | | |____PathParamsMetadata.java
| | | | |____FormMetadata.java
| | | | |____Hook.java
| | | | |____HTTPRequest.java
| | | | |____BigIntegerString.java
| | | |____models
| | | | |____operations
| | | | | |____DeletePetRequest.java
| | | | | |____GetPetByIdSecurity.java
| | | | | |____UpdateUserFormResponse.java
| | | | | |____CreateUserFormResponse.java
| | | | | |____LoginUserRequestBuilder.java
| | | | | |____UpdateUserRawRequestBuilder.java
| | | | | |____DeletePetResponse.java
| | | | | |____GetOrderByIdRequestBuilder.java
| | | | | |____SDKMethodInterfaces.java
| | | | | |____UpdateUserJsonRequestBuilder.java
| | | | | |____Status.java
| | | | | |____FindPetsByStatusRequest.java
| | | | | |____DeleteOrderRequestBuilder.java
| | | | | |____CreateUserJsonResponse.java
| | | | | |____UpdateUserJsonResponse.java
| | | | | |____DeleteOrderRequest.java
| | | | | |____UpdateUserRawResponse.java
| | | | | |____UpdatePetFormResponse.java
| | | | | |____PlaceOrderJsonRequestBuilder.java
| | | | | |____AddPetFormResponse.java
| | | | | |____PlaceOrderRawRequestBuilder.java
| | | | | |____UpdatePetJsonRequestBuilder.java
| | | | | |____FindPetsByStatusRequestBuilder.java
| | | | | |____CreateUserRawRequestBuilder.java
| | | | | |____LoginUserRequest.java
| | | | | |____FindPetsByTagsRequestBuilder.java
| | | | | |____FindPetsByTagsRequest.java
| | | | | |____LogoutUserResponse.java
| | | | | |____FindPetsByStatusResponse.java
| | | | | |____DeleteUserRequest.java
| | | | | |____UpdateUserRawRequest.java
| | | | | |____AddPetFormRequestBuilder.java
| | | | | |____GetInventorySecurity.java
| | | | | |____DeleteUserRequestBuilder.java
| | | | | |____CreateUsersWithListInputResponse.java
| | | | | |____DeleteOrderResponse.java
| | | | | |____UpdateUserJsonRequest.java
| | | | | |____GetPetByIdRequestBuilder.java
| | | | | |____CreateUserFormRequestBuilder.java
| | | | | |____CreateUserRawResponse.java
| | | | | |____AddPetJsonResponse.java
| | | | | |____UpdatePetJsonResponse.java
| | | | | |____GetOrderByIdResponse.java
| | | | | |____UploadFileResponse.java
| | | | | |____DeletePetRequestBuilder.java
| | | | | |____UpdatePetWithFormResponse.java
| | | | | |____PlaceOrderJsonResponse.java
| | | | | |____UpdateUserFormRequestBuilder.java
| | | | | |____LoginUserResponse.java
| | | | | |____UploadFileRequest.java
| | | | | |____LogoutUserRequestBuilder.java
| | | | | |____FindPetsByTagsResponse.java
| | | | | |____GetPetByIdResponse.java
| | | | | |____UpdatePetWithFormRequest.java
| | | | | |____GetPetByIdRequest.java
| | | | | |____UpdatePetRawResponse.java
| | | | | |____CreateUsersWithListInputRequestBuilder.java
| | | | | |____AddPetRawResponse.java
| | | | | |____PlaceOrderFormResponse.java
| | | | | |____GetUserByNameResponse.java
| | | | | |____UpdatePetWithFormRequestBuilder.java
| | | | | |____GetOrderByIdRequest.java
| | | | | |____GetInventoryResponse.java
| | | | | |____PlaceOrderFormRequestBuilder.java
| | | | | |____UploadFileRequestBuilder.java
| | | | | |____GetInventoryRequestBuilder.java
| | | | | |____UpdatePetFormRequestBuilder.java
| | | | | |____UpdatePetRawRequestBuilder.java
| | | | | |____DeleteUserResponse.java
| | | | | |____CreateUserJsonRequestBuilder.java
| | | | | |____GetUserByNameRequest.java
| | | | | |____AddPetJsonRequestBuilder.java
| | | | | |____AddPetRawRequestBuilder.java
| | | | | |____GetUserByNameRequestBuilder.java
| | | | | |____UpdateUserFormRequest.java
| | | | | |____PlaceOrderRawResponse.java
| | | | |____components
| | | | | |____Order.java
| | | | | |____Status.java
| | | | | |____Tag.java
| | | | | |____ApiResponse.java
| | | | | |____Pet.java
| | | | | |____OrderStatus.java
| | | | | |____Category.java
| | | | | |____User.java
| | | | | |____Security.java
| | | | |____errors
| | | | | |____SDKError.java
| | | |____Store.java
| | | |____SDKConfiguration.java
| | | |____SDK.java
```

Now run the following command for the OpenAPI Generator SDK folder:

```bash
cd petstore-sdk-java/src/main/java
tree
```

The OpenAPI Generator SDK structure looks like this:

```bash
|____org
| |____openapitools
| | |____client
| | | |____ApiClient.java
| | | |____ApiException.java
| | | |____ProgressResponseBody.java
| | | |____Pair.java
| | | |____GzipRequestInterceptor.java
| | | |____auth
| | | | |____RetryingOAuth.java
| | | | |____HttpBasicAuth.java
| | | | |____ApiKeyAuth.java
| | | | |____OAuth.java
| | | | |____OAuthOkHttpClient.java
| | | | |____Authentication.java
| | | | |____OAuthFlow.java
| | | | |____HttpBearerAuth.java
| | | |____ApiResponse.java
| | | |____JSON.java
| | | |____ServerVariable.java
| | | |____StringUtil.java
| | | |____Configuration.java
| | | |____ServerConfiguration.java
| | | |____model
| | | | |____Order.java
| | | | |____ModelApiResponse.java
| | | | |____Customer.java
| | | | |____Tag.java
| | | | |____Pet.java
| | | | |____AbstractOpenApiSchema.java
| | | | |____Category.java
| | | | |____User.java
| | | | |____Address.java
| | | |____api
| | | | |____PetApi.java
| | | | |____UserApi.java
| | | | |____StoreApi.java
| | | |____ApiCallback.java
| | | |____ProgressRequestBody.java
```

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.

```java
Pet req = Pet.builder()
    .name("Snoopie")
    .photoUrls(java.util.List.of(
            "https://some_url.com/snoopie1.jpg"))
    .id(1)
    .category(Category.builder()
        .id(1)
        .name("Dogs")
        .build())
    .tags(java.util.List.of(
        Tag.builder()
            .build()))
    .status(Status.AVAILABLE)
    .build();

UpdatePetJsonResponse res = sdk.pet().updatePetJson()
    .request(req)
    .call();

if (res.body().isPresent()) {
    // handle response
}
```

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:

```java
    ApiClient defaultClient = Configuration.getDefaultApiClient();
    defaultClient.setBasePath("/api/v3");

    // Configure OAuth2 access token for authorization: petstore_auth
    OAuth petstore_auth = (OAuth) defaultClient.getAuthentication("petstore_auth");
    petstore_auth.setAccessToken("YOUR ACCESS TOKEN");

    PetApi apiInstance = new PetApi(defaultClient);
    Pet pet = new Pet(); // Pet | Create a new pet in the store
    pet.setName("Snoopie");
    try {
      Pet result = apiInstance.addPet(pet);
      System.out.println(result);
    } catch (ApiException e) {
      System.err.println("Exception when calling PetApi#addPet");
      System.err.println("Status code: " + e.getCode());
      System.err.println("Reason: " + e.getResponseBody());
      System.err.println("Response headers: " + e.getResponseHeaders());
      e.printStackTrace();
    }
```

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.

```java
public class Pet {
    @JsonInclude(Include.NON_ABSENT)
    @JsonProperty("id")
    @SpeakeasyMetadata("form:name=id")
    private Optional<? extends Long> id;

    @JsonProperty("name")
    @SpeakeasyMetadata("form:name=name")
    private String name;

    @JsonInclude(Include.NON_ABSENT)
    @JsonProperty("category")
    @SpeakeasyMetadata("form:name=x")
    private Optional<? extends Category> category;

    @JsonProperty("photoUrls")
    @SpeakeasyMetadata("form:name=photoUrls")
    private java.util.List<String> photoUrls;

    //Rest of Pet.java ....
```

Compare this to the OpenAPI Generator SDK `Pet` model that uses Gson annotations:

```java
public class Pet {
  public static final String SERIALIZED_NAME_ID = "id";
  @SerializedName(SERIALIZED_NAME_ID)
  private Long id;

  public static final String SERIALIZED_NAME_NAME = "name";
  @SerializedName(SERIALIZED_NAME_NAME)
  private String name;

  public static final String SERIALIZED_NAME_CATEGORY = "category";
  @SerializedName(SERIALIZED_NAME_CATEGORY)
  private Category category;

  public static final String SERIALIZED_NAME_PHOTO_URLS = "photoUrls";
  @SerializedName(SERIALIZED_NAME_PHOTO_URLS)
  private List<String> photoUrls = new ArrayList<>();

  //Rest of Pet.java ....
```

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):

```java
  public Pet addPet(Pet pet) throws ApiException {
      ApiResponse<Pet> localVarResp = addPetWithHttpInfo(pet);
      return localVarResp.getData();
  }
```

The `addPet` method in turn calls the `addPetWithHttpInfo(pet)` method:

```java
  public ApiResponse<Pet> addPetWithHttpInfo(Pet pet) throws ApiException {
      okhttp3.Call localVarCall = addPetValidateBeforeCall(pet, null);
      Type localVarReturnType = new TypeToken<Pet>(){}.getType();
      return localVarApiClient.execute(localVarCall, localVarReturnType);
  }
```

Note how the method uses the `okhttp3.Call` object.

We examined the dependencies configured in the `build.gradle` file and discovered the `okhttp` dependency:

```groovy
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
```

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:

```java
HTTPRequest req = new HTTPRequest();
req.setMethod("POST");
req.setURL(url);
Object _convertedRequest = Utils.convertToShape(request, Utils.JsonShape.DEFAULT,
    new TypeReference<org.openapis.openapi.models.components.Pet>() {});
SerializedBody serializedRequestBody = org.openapis.openapi.utils.Utils.serializeRequestBody(
        _convertedRequest, "request", "json", false);
if (serializedRequestBody == null) {
    throw new Exception("Request body is required");
}
req.setBody(serializedRequestBody);

req.addHeader("Accept", "application/json;q=1, application/xml;q=0");
req.addHeader("user-agent", this.sdkConfiguration.userAgent);

HTTPClient client = org.openapis.openapi.utils.Utils.configureSecurityClient(
        this.sdkConfiguration.defaultClient, this.sdkConfiguration.securitySource.getSecurity());

HttpResponse<InputStream> httpRes = client.send(req);
```

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:

```java
import org.openapis.openapi.utils.HTTPClient;
import org.openapis.openapi.utils.HTTPRequest;
import java.net.http.HttpResponse;
```

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:

```java
import org.openapis.openapi.utils.HTTPClient;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.InputStream;

public class SpeakeasyHTTPClient implements HTTPClient {

    @Override
    public HttpResponse<InputStream> send(HttpRequest request)
            throws IOException, InterruptedException, URISyntaxException {
        HttpClient client = HttpClient.newHttpClient();
        return client.send(request, HttpResponse.BodyHandlers.ofInputStream());
    }
}
```

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:

```yaml