Jak poradzić sobie z nullami przy tworzeniu dto?

Odpowiedz Nowy wątek
2018-11-07 19:20
0

Klasa ClientDto wygląda tak:

public final class ClientDto {

    private Long id;
    private String login;
    private String nip;
    private String companyName;

    private String contactAddressCity;
    private String contactAddressStreet;
    private String contactAddressHouseNumberEtc;
    private String contactAddressPostalCode;

    private String registerAddressCity;
    private String registerAddressStreet;
    private String registerAddressHouseNumberEtc;
    private String registerAddressPostalCode;
// ...

jest tworzona z Client w której adresy nie muszą być podane, więc pojawia się nullpointerexception gdy mapuję dto tak:

@Override
    public ClientDto clientToDto(Client client) {
        ClientDto clientDto = new ClientDto();
        clientDto.setId(client.getId())
            .setLogin(client.getUser().getLogin())
            .setCompanyName(client.getCompanyName())
            .setContactAddressCity(client.getContactAddress().city)
            .setContactAddressHouseNumberEtc(client.getContactAddress().houseNumberEtc)
            .setContactAddressPostalCode(client.getContactAddress().postalCode)
            .setContactAddressStreet(client.getContactAddress().street)
            .setNip(client.getNip())
            .setRegisterAddressCity(client.getRegisterAddress().city)
            .setRegisterAddressHouseNumberEtc(client.getRegisterAddress().houseNumberEtc)
            .setRegisterAddressPostalCode(client.getRegisterAddress().postalCode)
            .setRegisterAddressStreet(client.getRegisterAddress().street);
        return clientDto;
    }

np. jak nie ma adresu to powinienem dostać jsona:

{
        "id": 2,
        "login": null,
        "nip": "9510525054",
        "companyName": "Janusz Soft sp. z o.o.",
        "contactAddressCity": null,
        "contactAddressStreet": null,
        "contactAddressHouseNumberEtc": null,
        "contactAddressPostalCode": null,
        "registerAddressCity": null,
        "registerAddressStreet": null,
        "registerAddressHouseNumberEtc": null,
        "registerAddressPostalCode": null
    }

Jak to sprytniej obsłużyć niż

@Override
    public ClientDto clientToDto(Client client) {
        ClientDto clientDto = new ClientDto();
        clientDto.setId(client.getId())
            .setLogin(client.getUser().getLogin())
            .setCompanyName(client.getCompanyName())
            .setNip(client.getNip());

             if(client.getContactAddress == null) {
                clientDto.setContactAddressCity(client.getContactAddress().city)
                    .setContactAddressHouseNumberEtc(client.getContactAddress().houseNumberEtc)
                    .setContactAddressPostalCode(client.getContactAddress().postalCode)
                    .setContactAddressStreet(client.getContactAddress().street)
             }

            if(client.getRegisterAddress == null) {
                clientDto.setRegisterAddressCity(client.getRegisterAddress().city)
                    .setRegisterAddressHouseNumberEtc(client.getRegisterAddress().houseNumberEtc)
                    .setRegisterAddressPostalCode(client.getRegisterAddress().postalCode)
                    .setRegisterAddressStreet(client.getRegisterAddress().street);
            }
        return clientDto;
    }

. W Encji jak dam Optionale do getterozy to mi się nic nie rozwali? A co jak mam publiczne metody, mam je robić Optionalami?
Krew mnie zalewa od tego JPA. Po 5 razy przepisuje się to samo.

edytowany 3x, ostatnio: Julian_, 2018-11-07 19:24

Pozostało 580 znaków

2018-11-07 19:36
eL
1

Ja bym zrobił np, tak...
Dodaj sobie jakiś GenericConverter, np.:

public interface GenericConverter<S,T>{

T getTarget(S s);

S getSource(T t);

A potem dodaj do niego implementację:

ClientConverter implements GenericConverter <Client, ClientDto> {
...
}

Potem te dane adresowe wyciągnij do jakiegoś AddressDto bo trochę wydaje mi się bezsensu trzymanie tego w Stringach. Jak potrzebujesz mieć to w JSONie bez zagnieżdżeń to jest na to adnotacja tylko teraz nie pamiętam. Spróbuj googlnąć a jak nie będziesz miał to poszukam.

Dodasz sobie też konwerter do tego adresu i konwerter zanim zacznie konwertować będzie sprawdzał czy przekazany obiekt nie jest null'em. Jeśli jest null to też zwróć null. Potem w tym ClientGenericConverter wykorzystaj też AddressConverter i wszystko powinno śmigać.

a ten GenericConverter to moge zrobić klasą abstrakcyjną? Bo jak rozumiem do takiego GenericConveter będę zawsze zapodawał w konstruktorze S i T? - Julian_ 2018-11-07 19:42
Nie bo to bezsensu. Robisz tylko Generyczny interfejs a potem implementujesz ten interfejs dla każdego obiektu jaki potrzebujesz konwertować. Podałem Ci przykład jak to zrobić z ClientConverter. Chyba że nie potrzebujesz tych konwerterów to możesz spokojnie DTO z bazy wyciągać od razu tak jak ktoś niżej pisze. Poczytaj np. o projekcjach. - eL 2018-11-07 19:46

Pozostało 580 znaków

2018-11-07 19:37
0

Jeżeli już korzystasz z JPA to możesz zwracać dto od razu z zapytania.

https://stackoverflow.com/que[...]nate-hql-multiple-new-objects

edytowany 1x, ostatnio: Seti87, 2018-11-07 19:43
nie czaję jakby to miało wyglądać... masz jakiś przykład z całym kodem? - Julian_ 2018-11-07 19:53
opiszę w nowym poście - Seti87 2018-11-08 12:13

Pozostało 580 znaków

2018-11-07 19:37
1

Najlepiej to w Kotlinie a jak Java to pozostaje płakać i sprawdzać nulle z ręki, ew. Optionalem możesz użyć Optional.ofNullable(client.getAddress()). gdybyś zrobił sobie klasę AddressDto i użył jej w ClientDtoo dla obu adresów, to też byłoby łatwiej.

Pozostało 580 znaków

2018-11-07 19:41
0

A czemu to DTO takie płaskie?


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
może lubi deski? :D - Merylin 2018-11-07 19:43

Pozostało 580 znaków

2018-11-07 19:42
eL
1

Spłaszczenie Jsona o ktorym pisałem mozesz zrobic dodajac adnotacje: @JsonUnwrapped

dziękuję Pieseł. - Julian_ 2018-11-07 19:43

Pozostało 580 znaków

2018-11-07 22:08
0

a dto też testujecie jednostkowymi? Szału dostanę z tym pisaniem assertEquals(x.getValue(), y.setValue(x.getValue()).getValue());

Testy powinny pokrywać zachowanie. DTO nie mają zachowania, ergo - nie ma potrzeby pisania do nich testów. - Patryk27 2018-11-07 22:43

Pozostało 580 znaków

2018-11-07 22:34
1

Przecież to proste, ja robie taki test:

var systemik  = wszechświat.postawMójSystemik();
var walniętySystem = systemik.walnijMuTakiegoPOSTa(ŁoRanyJakiPost);
var klientDtoJakoJson  = walniętySystem .weźNoGETemKlientaNr(2);
assertEquals( oczekiwanyJson, klientDtoJakoJson  );

Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
to napisała ta twoja magiczna klawiatura? ze śmiechu nie mogłem jak oglądałem tę prezentację - discoStar 2018-11-08 00:28

Pozostało 580 znaków

2018-11-07 23:27
0
jarekr000000 napisał(a):

Przecież to proste, ja robie taki test:

var systemik  = wszechświat.postawMójSystemik();
var walniętySystem = systemik.walnijMuTakiegoPOSTa(ŁoRanyJakiPost);
var klientDtoJakoJson  = walniętySystem .weźNoGETemKlientaNr(2);
assertEquals( oczekiwanyJson, klientDtoJakoJson  );

ta... 70 linijek jak w mordę strzelił

public class AddressMapperTest {

    GenericMapper<Address, AddressDto> mapper;

    @Before
    public void setUp() {
        this.mapper = new AddressMapper();
    }

    @Test
    public void testNull() {
        // given
        Address address = null;
        AddressDto dto = null;

        // when
        AddressDto dtoFromAddress = mapper.sourceToDto(address);
        Address addressFromDto = mapper.dtoToNewSource(dto);
        Address addressFromDtoAndAdress = mapper.dtoToUpdatedSource(address, dto);

        // then
        assertNull(dtoFromAddress);
        assertNull(addressFromDto);
        assertNull(addressFromDtoAndAdress);
    }

    @Test
    public void testEmpty() {
        // given
        AddressDto dto = new AddressDto();

        // when
        Address addressFromDto = mapper.dtoToNewSource(dto);

        // then
        assertNotNull(addressFromDto);
    }

    @Test
    public void testSourceToDto() {
        // given
        Address address = new Address("a", "b", "c", "00-001");

        // when
        AddressDto dto = mapper.sourceToDto(address);

        // then
        assertEquals("a", dto.getCity());
        assertEquals("b", dto.getStreet());
        assertEquals("c", dto.getHouseNumberEtc());
        assertEquals("00-001", dto.getPostalCode());
    }

    @Test
    public void testDtoToNewSource() {
        // given
        AddressDto dto = new AddressDto();
        dto.setCity("a").setHouseNumberEtc("1b").setStreet("c").setPostalCode("00-001");

        // when
        Address addressFromDto = mapper.dtoToNewSource(dto);

        // then
        assertEquals("a", addressFromDto.city);
        assertEquals("1b", addressFromDto.houseNumberEtc);
        assertEquals("c", addressFromDto.street);
        assertEquals("00-001", addressFromDto.postalCode);
    }

    @Test
    public void testDtoToUpdatedSource() {
        testDtoToNewSource();
    }

}

Pozostało 580 znaków

2018-11-07 23:48
1

Zdziwiony? Przecież zrobiłeś dokładnie inaczej niż pisalem.
Tłumaczę raz jeszcze:

assertEquals( oczekiwanyJson, klientDtoJakoJson  )

czyli

assertEquals( """{ "city" : "a", "street": "b", "houseNumberEtc":"c" ... .} """, klientDtoJakoJson  )

Jak masz mappery to najłatwiej testować całościowo.

Jeszcze jeden trik.

assertEquals( expectedDto, mapper(dbObject))

O ile tylko dto ma equals (a to proste).


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 2x, ostatnio: jarekr000000, 2018-11-07 23:54
zobaczyłem spocka to nie czytałem. - Julian_ 2018-11-07 23:50
tam nawet nie było Spocka - jarekr000000 2018-11-07 23:51
no to kotlin - Julian_ 2018-11-07 23:52
to na górze to akurat była Java. W kotlinie nie napisałbym var przecież. No i średniki !!! - jarekr000000 2018-11-07 23:53
aa, ja tam robię w 8 - Julian_ 2018-11-07 23:55
Wrzuć sobie 10. - eL 2018-11-08 09:24

Pozostało 580 znaków

2018-11-08 01:08
1

Na bootcampie to my używamy MapStruct'a.

Co to za nik buhaha. - ._. 2018-11-12 18:23

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0