Skip to content

Instantly share code, notes, and snippets.

@stevenwaterman
Created December 27, 2019 14:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenwaterman/28f0ec03a0cc0370a3b0c9351917976b to your computer and use it in GitHub Desktop.
Save stevenwaterman/28f0ec03a0cc0370a3b0c9351917976b to your computer and use it in GitHub Desktop.
Perfect Spring DTO (ours)
package com.scottlogic.springdto;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Positive;
import lombok.Value;
public class Example {
public enum ProductDto{;
public interface Id{
/**
* The identifier for this product.
* IDs are unique amongst products but may be
* repeated across other entity types
*/
@Positive
Long getId();
}
public interface Name{
/**
* The product's name as should appear on the site.
* Any capitalisation here should be stored in the
* database but any filtering should be case-insensitive.
*/
@NotBlank
String getName();
}
public interface Price{
/**
* The amount that we sell a product for in GBP.
* This includes our margin but should not include
* any delivery fees or VAT.
*/
@Positive
Double getPrice();
}
public interface Cost{
/**
* The amount that it costs us to purchase this product
* For the amount we sell a product for, see {@link Price}.
* <b>This data is confidential</b>
*/
@Positive
Double getCost();
}
public enum Request{;
@Value public static class Create implements Name, Price, Cost{
String name;
Double price;
Double cost;
}
}
public enum Response{;
@Value public static class Public implements Id, Name, Price{
Long id;
String name;
Double price;
}
@Value public static class Private implements Id, Name, Price, Cost{
Long id;
String name;
Double price;
Double cost;
}
}
private static <DTO extends Price & Cost> Double getMarkup(DTO dto){
return (dto.getPrice() - dto.getCost()) / dto.getCost();
}
}
}
@brunodrugowick
Copy link

brunodrugowick commented Jun 19, 2020

I think you could expand to show an example just a bit more complex, like, returning the following representation:

{
    "postalCode": "13020",
    "addressLine_1": "Cocada Street, 123456",
    "addressLine_2": "Neighborhood",
    "region": "Region1",
    "city": {
      "name": "São José dos Campos",
      "province": "São Paulo"
    }
}

I ended up with something like this:

package dev.drugowick.algaworks.algafoodapi.api.model.dtoPattern;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

public enum AddressDTO {;

    private interface PostalCode { String getPostalCode(); }
    private interface AddressLine_1 { String getAddressLine_1(); }
    private interface AddressLine_2 { String getAddressLine_2(); }
    private interface Region { String getRegion(); }
    private interface City { CityDTO.Default getCity(); }

    private enum CityDTO {;

        private interface Name { String getName(); }
        private interface Province { String getProvince(); }

        @Getter @Setter @NoArgsConstructor
        private static class Default implements Name, Province {
            String name;
            String province;
        }

    }

    public enum Response {;
        @Getter @Setter @NoArgsConstructor
        public static class Default implements PostalCode, AddressLine_1, AddressLine_2, Region, City {
            String postalCode;
            String addressLine_1;
            String addressLine_2;
            String region;
            CityDTO.Default city;
        }
    }
}

Does this makes sense?

@brunodrugowick
Copy link

Actually, I think I'm mixing things up... you don't mention transformation of the domain objects to DTOs.

I still want to hear what you have to say about the previous structure, so I'll keep the comment. =)

@TcheORfabio
Copy link

I have the same question of @brunodrugowick, how do you go from a model to a dto like this?

@MagnusSmith
Copy link

I might suggest that records would be an nicer fit removing the need for the static classes and the lombok annotations while maintaining immutability. For even more conciseness take a look at the @RecordInterface part of RecordBuilder here https://github.com/Randgalt/record-builder#RecordInterface-Example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment