Mapstruct - dificuldade com mapeamento

Boa noite pessoal

Tenho um projeto (spring boot, jpa) com duas classes, Car e Person, mapeadas no banco de dados com relacionamento one-to-one por meio de uma tabela intermediária. Esse relacionamento é opcional, ou seja, uma classe pode existir sem a outra.

As classes:

package examples.model;

import lombok.Data;

@Data
public class Car {

private int id;
private Person owner;
private int numerOfWheels;
private int seatingCapacity;
private double maximumVelocity;
}

package examples.dto;

import lombok.Data;

@Data
public class CarDTO {

private String id;
private String ownerId;
private String numerOfWheels;
private String seatingCapacity;
private String maximumVelocity;
}

package examples.model;

import lombok.Data;

@Data
public class Person {

private int id;
private String name;
private int age;
}

package examples.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

import examples.dto.CarDTO;
import examples.model.Car;

@Mapper
public interface CarMapper {

CarMapper MAPPER = Mappers.getMapper(CarMapper.class);

@Mapping(source = “dto.ownerId”, target = “owner.id”)
Car toModel(CarDTO dto);
}

O que eu preciso é que Car.owner == null quando CarDTO.ownerId == null, ou seja, quando não for informado o id do proprietário, o atributo owner da classe Car seja nulo, senão não conseguirei persistir o objeto Car no banco de dados com um atributo <Person(id=0, name=null, age=0)>

A classe de mapeamento gerada pelo mapstruct:

package examples.mapper;

import examples.dto.CarDTO;
import examples.model.Car;
import examples.model.Person;
import javax.annotation.processing.Generated;

@Generated(
value = “org.mapstruct.ap.MappingProcessor”,
date = “2021-08-03T23:26:30-0300”,
comments = “version: 1.5.0.Beta1, compiler: Eclipse JDT (IDE) 1.3.1300.v20210419-1022, environment: Java 11.0.11 (Ubuntu)”
)
public class CarMapperImpl implements CarMapper {

@Override
public Car toModel(CarDTO dto) {
    if ( dto == null ) {
        return null;
    }

    Car car = new Car();

    car.setOwner( carDTOToPerson( dto ) );
    if ( dto.getId() != null ) {
        car.setId( Integer.parseInt( dto.getId() ) );
    }
    if ( dto.getMaximumVelocity() != null ) {
        car.setMaximumVelocity( Double.parseDouble( dto.getMaximumVelocity() ) );
    }
    if ( dto.getNumerOfWheels() != null ) {
        car.setNumerOfWheels( Integer.parseInt( dto.getNumerOfWheels() ) );
    }
    if ( dto.getSeatingCapacity() != null ) {
        car.setSeatingCapacity( Integer.parseInt( dto.getSeatingCapacity() ) );
    }

    return car;
}

protected Person carDTOToPerson(CarDTO carDTO) {
    if ( carDTO == null ) {
        return null;
    }

    Person person = new Person();

    if ( carDTO.getOwnerId() != null ) {
        person.setId( Integer.parseInt( carDTO.getOwnerId() ) );
    }

    return person;
}

}

O teste:

package examples;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

import examples.dto.CarDTO;
import examples.mapper.CarMapper;
import examples.model.Car;

class CarMapperTest {

@Test
public void testMapDtoToEntity() {

  CarDTO carDTO = new CarDTO();
  carDTO.setMaximumVelocity("115.2");
  carDTO.setNumerOfWheels("4");
  carDTO.setSeatingCapacity("5");
  
  Car car = CarMapper.MAPPER.toModel(carDTO);
  
  assertEquals(115.2, car.getMaximumVelocity() );
  assertEquals(4, car.getNumerOfWheels() );
  assertEquals(5, car.getSeatingCapacity());
  assertEquals(null, car.getOwner());

}

}

O resultado:

org.opentest4j.AssertionFailedError: expected: but was: <Person(id=0, name=null, age=0)>

Vejam que quando não é passado o id do proprietário, o mapstruct instancia um objeto da classe Person e coloca no atributo Car.owner

Alguém consegue me ajudar a fazer esse mapeamento?

Obrigado :slight_smile:

Usa um expression, já deve resolver!

Exemplo:
https://stackoverflow.com/questions/62597010/mapstruct-mappingexpression-java