DEV Community

Partha Sutradhar
Partha Sutradhar

Posted on • Updated on

Building Generic Payloads with the Builder Pattern in Java

Java Generics can be used to create reusable code for structured responses in web services. This makes the code easier to maintain and scale. Generics allows the Payload class to be flexible, reusable, and consistent for backend and client-side developers.

Introduction

A well-structured response from a backend service provides clear information about the outcome of the request, any relevant data, any associated messages, and often metadata such as the timestamp.

Structured responses from backend services

A well-structured response from a backend service:

  • Provides clarity about the outcome (success or failure).
  • Contains any relevant data related to the response.
  • May provide any associated message with the response.
  • Often includes metadata, like the timestamp.

Using Generics to define a response

Consider the Payload class provided. Here's a breakdown of how it's structured:

  • Message: A description of the outcome of the request, such as "Request Successful" or "Item not found."
  • Status: A numerical status code, such as 200 for OK or 404 for NOT FOUND.
  • Payload: The actual data being sent in the response. This can be of any type, thanks to the use of Generics.
  • Timestamp: The time at which the response was created.

In short: The Payload class provides a structured way to represent backend responses, with fields for the message, status, payload, and timestamp.

Using the Builder Pattern

The builder pattern allows us to construct Payload objects in a more expressive way, as shown in the following example:

Payload<String> successPayload = new Payload.Builder<String>()
                                    .message("Request successful")
                                    .status(PayloadStatus.SUCCESS)
                                    .payload("This is the response data")
                                    .build();

Enter fullscreen mode Exit fullscreen mode

Benefits

  • Flexible: Payload can be of any type, thanks to Generics.
  • Reusable: A single Payload class can be used for many different response types.
  • Consistent: All responses have a consistent structure.

Usage

// Create a Payload with a String payload.
Payload<String> successPayload = new Payload.Builder<String>()
  .message("Request successful")
  .status(PayloadStatus.SUCCESS)
  .payload("This is the response data")
  .build();

// Create a Payload with a User object payload.
User user = new User("John", "Doe");
Payload<User> userPayload = new Payload.Builder<User>()
  .status(PayloadStatus.SUCCESS)
  .message("User found")
  .payload(user)
  .build();

// Create a Payload with a List of Items payload.
List<Item> items = Arrays.asList(new Item("Book"), new Item("Pen"));
Payload<List<Item>> itemsPayload = new Payload.Builder<List<Item>>()
  .status(PayloadStatus.SUCCESS)
  .message("Items fetched")
  .payload(items)
  .build();

// Create a Payload with an error message.
Payload<Void> errorPayload = new Payload.Builder<Void>()
  .status(PayloadStatus.ERROR)
  .message("Something went wrong!")
  .build();
Enter fullscreen mode Exit fullscreen mode

Payload Builder Pattern

The Payload Builder Pattern is a design pattern that allows you to create complex objects in a step-by-step manner. It is especially useful for creating objects with many optional parameters.

@Getter
@ToString
public class Payload<T> {
    private final String message;
    private final int status;
    private final T payload;
    private final Date timestamp;

    private Payload(PayloadStatus status, String message, T payload) {
        this.status = status.getCode();
        this.message = message;
        this.payload = payload;
        this.timestamp = Date.from(Instant.now().atZone(ZoneId.of("UTC")).toInstant());
    }

    public static class Builder<T> {
        private String message;
        private PayloadStatus status;
        private T payload;

        public Builder<T> message(String message) {
            this.message = message;
            return this;
        }

        public Builder<T> status(PayloadStatus status) {
            this.status = status;
            return this;
        }

        public Builder<T> payload(T payload) {
            this.payload = payload;
            return this;
        }

        public Payload<T> build() {
            return new Payload<>(status, message, payload);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

The Payload class with builder pattern is a flexible, reusable, and consistent way to represent responses from a backend service. It is easy to use and can be applied to a variety of use cases.

Top comments (13)

Collapse
 
siy profile image
Sergiy Yevtushenko

Builder pattern can be used only to optional parameters. Otherwise, it may result in uninitialized values and NPE.

Collapse
 
parthasutradhar profile image
Partha Sutradhar

Thanks Sergiy. Yes, it'll result in NPE without optional params. Let me know if we can do something to fix this?

Collapse
 
siy profile image
Sergiy Yevtushenko

There is a Fluent Builder pattern, suitable for cases when all (or majority) of parameters are required. You may find interesting this article.

Thread Thread
 
parthasutradhar profile image
Partha Sutradhar • Edited

Yes, Step Builder will force client to provide datum.

Thread Thread
 
siy profile image
Sergiy Yevtushenko

Moreover, this pattern enforces order in which fields are assigned. This is helpful in many situations, especially when changes in code are compared.

Collapse
 
masum profile image
Abdullah Al Masum

Awesome content. We may now implement this pattern similarly in Asp.Net Core. Hope this architecture-related article continues.

Collapse
 
parthasutradhar profile image
Partha Sutradhar

Thanks Masum. I'll try to update on this type of article.

Collapse
 
anupamakib profile image
Mir Anupam Hossain Akib

Nicely explained. It will help me to learn Builder Patterns. Thanks for the article.

Collapse
 
parthasutradhar profile image
Partha Sutradhar

Thanks, Anupam for your feedback. I'll update regularly on this.

Collapse
 
khair_al_anam profile image
Khair Alanam

This is such an informative article on Builder Patterns! The code snippets shown are pretty good :D and really explains the use of Payload with Builder Pattern.

Collapse
 
parthasutradhar profile image
Partha Sutradhar

Thanks, Alanam. I'll try to update regularly on Java Design Pattern's and on Software Architecture.

Collapse
 
pathus90 profile image
Diallo Mamadou Pathé

Nice article.
Lombok has an annotation @builder.

Might be usefull And can reduce boilerplate code

Collapse
 
parthasutradhar profile image
Partha Sutradhar

Thanks Pathe. Will try using this from now on.