Package se.arkalix.dto

Data Transfer Object Utilities

This package contains various utilities useful for constructing so-called Data Transfer Objects (DTOs). In essence, a DTO is a well-defined set of data that needs to be represented on an external medium, such as a hard drive or a network wire. As such, a DTO must be readable and/or writable from/to a particular machine-independent representation, or encoding.

While there are many libraries and other solutions for dealing with the problem of encoding and decoding what practically amounts to Plain-Old Java Objects (POJOs), this particular package distinguishes itself from many of them by centering around the idea that as much as possible of the cost of converting POJOs to and from their encoded forms should be paid at compile- time rather than at runtime. For this reason this package depends on the availability of the kalix-processors package, which concretely looks up the annotations of this package and uses whatever is annotated as input for generating the code required for reading and/or writing POJOs with certain encodings.

Using the DTO code generation capabilities entails defining so-called, DTO interface types and then using the DTO interface (1) classes and (2) builders generated from those DTO interface types.

DTO Interface Types

A DTO interface type is a plain Java interface that satisfies the following constraints:
  1. It has no generic type parameters.
  2. Its name does not end with "Dto".
  3. It is annotated with either @DtoReadableAs or @DtoWritableAs, and whichever of those annotations are present are given at least one DtoEncoding as arguments.
  4. It contains only static, default and getter methods, where a getter is a method that takes no arguments and returns a type that is not void.
  5. The return type of each getter method belongs to one of the following categories:
    1. Primitives, such as int or boolean.
    2. Boxed primitives, such as Integer or Boolean.
    3. BigInteger and BigDecimal.
    4. String.
    5. Arrays, such as new int[]{1,2,3}.
    6. List<T>, where T is any type mentioned in this list except for Optional<T>.
    7. Map<K, V>, where K is a primitive, boxed primitive, String, enum, enum-like or a java.time temporal class and V is any type mentioned in this list except for Optional<T>.
    8. Java enums.
    9. So-called enum-likes, which is are normal classes that override equals(), hashCode() and toString(), as well as having public static valueOf(String) methods.
    10. Other DTO interfaces.
    11. Optional<T>, where T is any type mentioned in this list except for Optional<T>.
    12. Any non-local java.time temporal type, such as Instant and Duration. Note that Date is not supported.
    13. So-called custom types, which typically are exclusive to a particular encoding, such as JsonObject, which may only be used by DTO interfaces that can only be read/written from/to JSON.
The following is an example of a valid DTO interface declaration:
     @DtoReadableAs(DtoEncoding.JSON)
     public interface Message {
         String title();
         List<String> texts();
         Instant sentAt();
     }
 

DTO Interface Classes and Builders

When a DTO interface has been successfully processed by the kalix-processors package and compilation succeeded, two new generated classes will exist. Please make sure that whatever folder they end up in is included in the Java classpath to make them usable from within your application. The names of the generated classes will end with "Dto" and "Builder". In the case of the above example, the names of the generated classes would be "MessageDto" and "MessageBuilder".

The "Dto" class concretely holds the data specified in the DTO interface in the form of getters, while the "Builder" class is used for creating "Dto" instances. "Dto" classes are always immutable, meaning that once constructed their contents can never change. Additionally, whenever a "Builder" attempts to create a "Dto" instance, the inputs it were given are validated to make sure that no non-optional data is missing.

Here follows an example of using the builder associated with the above example to construct a valid "Dto" class:

     final var message = new MessageBuilder()
         .title("Hello, Arrowhead!")
         .texts("Text 1", "Text 2", "Text 3")
         .sentAt(Instant.now())
         .build();

     // Print message title to see that it worked.
     System.out.println(message.title());