Jak poradzić sobie z nullami przy tworzeniu dto?

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.

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ć.

0

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

https://stackoverflow.com/questions/40218903/hibernate-hql-multiple-new-objects

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.

0

A czemu to DTO takie płaskie?

1

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

0

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

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  );
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();
	}

}
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).

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