jueves, 26 de mayo de 2022

MapStruct walking to map between java beans 3

 


MapStruct walking to map between java beans 3

https://github.com/jalbertomr/mapStructDemo

Company has a natural collection of Employee, the CompanyMapper uses EmployeeMapper


CompanyMapper


@Mapper(uses=EmployeeMapper.class)
public interface CompanyMapper {
CompanyDto companyToDto(Company company);
}

The Code autogenerated for CompanyMapper


@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-26T19:07:18-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class CompanyMapperImpl implements CompanyMapper {

private final EmployeeMapper employeeMapper = Mappers.getMapper( EmployeeMapper.class );

@Override
public CompanyDto companyToDto(Company company) {
if ( company == null ) {
return null;
}

CompanyDto companyDto = new CompanyDto();

companyDto.setEmployees( employeeMapper.employeesListToDto( company.getEmployees() ) );

return companyDto;
}
}

CompanyMapper with a specific CollectionStrategy 

@Mapper(uses= EmployeeMapper.class, collectionMappingStrategy= CollectionMappingStrategy.ADDER_PREFERRED)
public interface CompanyMapperAdderPreferred {
CompanyDto companyToDto(Company company);
}

The Code autogenerated for CompanyMapper with CollectionStrategy


@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-26T19:07:18-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class CompanyMapperAdderPreferredImpl implements CompanyMapperAdderPreferred {

private final EmployeeMapper employeeMapper = Mappers.getMapper( EmployeeMapper.class );

@Override
public CompanyDto companyToDto(Company company) {
if ( company == null ) {
return null;
}

CompanyDto companyDto = new CompanyDto();

if ( company.getEmployees() != null ) {
for ( Employee employee : company.getEmployees() ) {
companyDto.addEmployee( employeeMapper.employeeToDto( employee ) );
}
}

return companyDto;
}
}
@Tests

@Slf4j
class CompanyMapperTest {
private CompanyMapper companyMapper = Mappers.getMapper(CompanyMapper.class);

@Test
void companyToDtoTest() throws ParseException {
//given
Division division = new Division(1, "North");
Date startDate = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss").parse("2022-06-01 09:00:05");
Employee employee = new Employee(33L, "Jose Alberto", "Martinez", division, startDate);
Company company = new Company();
company.addEmployee(employee);
//when
CompanyDto companyDto = companyMapper.companyToDto(company);
log.info("company: {}", company);
log.info("companyDto: {}", companyDto);
//Then
Assertions.assertEquals(company.getEmployees().get(0).getDivision().getName(),companyDto.getEmployees().get(0).getDivisionDto().getName()
);
//...
}
}


eot

MapStruct walking to map between java beans 2


MapStruct walking to map between java beans 2

https://github.com/jalbertomr/mapStructDemo

Employee and Division and his respective figurative DTOs, check the divergency in employee name, the diferent type of the dates.


Convertion between dates are required and is done by DateConverter class.


@Component
public class DateConverter {
private final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
private final DateTimeFormatter DATETIMEFORMATER = DateTimeFormatter.ofPattern(DATETIME_FORMAT);

public Date strDateTimeToDate(String strDateTime) throws ParseException {
return new SimpleDateFormat(DATETIME_FORMAT).parse(strDateTime);
};

public String dateToStrDateTime(Date date){ return new SimpleDateFormat( DATETIME_FORMAT).format( date);
}

public LocalDateTime stringAsLocalDateTime(String str) {
return LocalDateTime.parse( str, DATETIMEFORMATER);
}

public String localDateTimeAsString( LocalDateTime dateTime) {
return dateTime.format(DATETIMEFORMATER);
}

public Date localDateTimeToDate(LocalDateTime localDateTime){
return //java.util.Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
java.sql.Timestamp.valueOf(localDateTime);
}

public LocalDateTime dateToLocalDateTime( Date date){
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}

}

The EmployeeMapper declare the use of DateConverter and also uses Collections


@Mapper(uses= DateConverter.class)
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);

@Mapping(source = "id", target = "employeeId")
@Mapping(target = "employeeName", expression = "java(employee.getFirstName() + \" \" + employee.getLastName() )")
@Mapping(source = "startDate", target = "employeeStartDate", dateFormat = "YYYY-mm-dd HH:mm:ss")
@Mapping(source = "employee.division.id", target="divisionDto.id")
EmployeeDto employeeToDto(Employee employee);

@Mapping(source = "employeeId", target = "id")
@Mapping(target = "firstName", expression = "java(employeeDto.getEmployeeName() )")
@Mapping(target = "lastName", expression = "java(employeeDto.getEmployeeName() )")
@Mapping(source = "employeeStartDate", target = "startDate", dateFormat = "YYYY-mm-dd HH:mm:ss")
@Mapping(source="employeeDto.divisionDto.id", target="division.id")
@Mapping(source="employeeDto.divisionDto.name", target="division.name")
Employee employeeDtoToEmployee(EmployeeDto employeeDto);

List<EmployeeDto> employeesListToDto(List<Employee> employees);

Set<EmployeeDto> employeesSetToDto(Set<Employee> employees);

Map<String, EmployeeDto> employeesMapToDto(Map<String, Employee> employee);
}

The Code Generated shows the details on the conversions.


@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-26T19:07:17-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class EmployeeMapperImpl implements EmployeeMapper {

private final DateConverter dateConverter = new DateConverter();

@Override
public EmployeeDto employeeToDto(Employee employee) {
if ( employee == null ) {
return null;
}

EmployeeDto employeeDto = new EmployeeDto();

employeeDto.setDivisionDto( divisionToDivisionDto( employee.getDivision() ) );
employeeDto.setEmployeeId( employee.getId() );
employeeDto.setEmployeeStartDate( dateConverter.dateToStrDateTime( employee.getStartDate() ) );

employeeDto.setEmployeeName( employee.getFirstName() + " " + employee.getLastName() );

return employeeDto;
}

@Override
public Employee employeeDtoToEmployee(EmployeeDto employeeDto) {
if ( employeeDto == null ) {
return null;
}

Employee employee = new Employee();

employee.setDivision( divisionDtoToDivision( employeeDto.getDivisionDto() ) );
employee.setId( employeeDto.getEmployeeId() );
try {
employee.setStartDate( dateConverter.strDateTimeToDate( employeeDto.getEmployeeStartDate() ) );
}
catch ( ParseException e ) {
throw new RuntimeException( e );
}

employee.setFirstName( employeeDto.getEmployeeName() );
employee.setLastName( employeeDto.getEmployeeName() );

return employee;
}

@Override
public List<EmployeeDto> employeesListToDto(List<Employee> employees) {
if ( employees == null ) {
return null;
}

List<EmployeeDto> list = new ArrayList<EmployeeDto>( employees.size() );
for ( Employee employee : employees ) {
list.add( employeeToDto( employee ) );
}

return list;
}

@Override
public Set<EmployeeDto> employeesSetToDto(Set<Employee> employees) {
if ( employees == null ) {
return null;
}

Set<EmployeeDto> set = new HashSet<EmployeeDto>( Math.max( (int) ( employees.size() / .75f ) + 1, 16 ) );
for ( Employee employee : employees ) {
set.add( employeeToDto( employee ) );
}

return set;
}

@Override
public Map<String, EmployeeDto> employeesMapToDto(Map<String, Employee> employee) {
if ( employee == null ) {
return null;
}

Map<String, EmployeeDto> map = new HashMap<String, EmployeeDto>( Math.max( (int) ( employee.size() / .75f ) + 1, 16 ) );

for ( java.util.Map.Entry<String, Employee> entry : employee.entrySet() ) {
String key = entry.getKey();
EmployeeDto value = employeeToDto( entry.getValue() );
map.put( key, value );
}

return map;
}

protected DivisionDto divisionToDivisionDto(Division division) {
if ( division == null ) {
return null;
}

DivisionDto divisionDto = new DivisionDto();

divisionDto.setId( division.getId() );
divisionDto.setName( division.getName() );

return divisionDto;
}

protected Division divisionDtoToDivision(DivisionDto divisionDto) {
if ( divisionDto == null ) {
return null;
}

Division division = new Division();

division.setId( divisionDto.getId() );
division.setName( divisionDto.getName() );

return division;
}
}

The @Tests

@Slf4j
class EmployeeMapperTest {

@Test //Employee -> EmployeeDto
void mapEmployeeTest() throws ParseException {
//given
Division division = new Division(1, "North");
Date startDate = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss").parse("2022-06-01 09:00:05");
Employee employee = new Employee( 23, "Jose Alberto", "Martinez", division, startDate);
//when
EmployeeDto employeeDto = EmployeeMapper.INSTANCE.employeeToDto(employee);
log.info("employee: {}", employee);
log.info("employeeDto: {}", employeeDto);
//then
Assertions.assertEquals(23, employeeDto.getEmployeeId());
Assertions.assertEquals( employee.getFirstName() + " " + employee.getLastName(), employeeDto.getEmployeeName());
Assertions.assertEquals( division.getId(), employeeDto.getDivisionDto().getId());
Assertions.assertEquals( division.getName(), employeeDto.getDivisionDto().getName());
}

@Test
void employeeDtoToEmployeeTest() {
//given
DivisionDto divisionDto = new DivisionDto(3,"PACIFIC","WESTERN");
EmployeeDto employeeDto = new EmployeeDto(102, "Jose Alberto Martinez", divisionDto, "2022-06-01 09:10:05");
Employee employee = EmployeeMapper.INSTANCE.employeeDtoToEmployee(employeeDto);
//then
log.info("employeeDto: {}", employeeDto);
log.info("employee: [{}]", employee);
Assertions.assertEquals(employee.getId(), employeeDto.getEmployeeId());
Assertions.assertEquals(employee.getFirstName(), employeeDto.getEmployeeName());
Assertions.assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(employee.getStartDate()), employeeDto.getEmployeeStartDate());
Assertions.assertEquals(employee.getDivision().getId(),employeeDto.getDivisionDto().getId());
Assertions.assertEquals(employee.getDivision().getName(),employeeDto.getDivisionDto().getName());
}

@Test
void employeesListToDto() throws ParseException {
//given
Division division = new Division(1, "North");
Date startDate = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss").parse("2022-06-01 09:00:05");
Employee employee = new Employee(33L, "Jose Alberto", "Martinez", division, startDate);
List<Employee> employees = new ArrayList<>();
employees.add(employee);
//when
List<EmployeeDto> employeesDto = EmployeeMapper.INSTANCE.employeesListToDto(employees);
//then
System.out.println(employees);
System.out.println(employeesDto);

Assertions.assertEquals(employees.get(0).getId(), employeesDto.get(0).getEmployeeId());
Assertions.assertEquals(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(employees.get(0).getStartDate()),employeesDto.get(0).getEmployeeStartDate());
Assertions.assertEquals(employees.get(0).getDivision().getName(),employeesDto.get(0).getDivisionDto().getName());
//...
}

@Test
void employeesSetToDto() throws ParseException {
//given
Division division = new Division(1, "North");
Date startDate = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss").parse("2022-06-01 09:00:05");
Employee employee = new Employee(33L, "Jose Alberto", "Martinez", division, startDate);
Set<Employee> employeesSet = new HashSet<>();
employeesSet.add( employee);
//when
Set<EmployeeDto> employeesDtoSet = EmployeeMapper.INSTANCE.employeesSetToDto(employeesSet);
log.info("employeesSet: {} ", employeesSet);
log.info("employeesDtoSet: {} ", employeesDtoSet);
//then
Assertions.assertEquals(employeesSet.iterator().next().getDivision().getName(),employeesDtoSet.iterator().next().getDivisionDto().getName());
//...
}

@Test
void employeesMaoToDto() throws ParseException {
//given
Division division = new Division(1, "North");
Date startDate = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss").parse("2022-06-01 09:00:05");
Employee employee = new Employee(33L, "Jose Alberto", "Martinez", division, startDate);
Map<String,Employee> employeesMap = new HashMap<>();
employeesMap.put("emp1" ,employee);
//when
Map<String,EmployeeDto> employeesDtoMap = EmployeeMapper.INSTANCE.employeesMapToDto(employeesMap);
log.info("employeesMap: {} ", employeesMap);
log.info("employeesDtoMap: {} ", employeesDtoMap);
//then
Assertions.assertEquals(employeesMap.get("emp1").getDivision().getName(),employeesDtoMap.get("emp1").getDivisionDto().getName());
}
}


eot

martes, 24 de mayo de 2022

MapStruct walking to map between java beans 1

MapStruct walking to map between java beans

https://github.com/jalbertomr/mapStructDemo

- Maven setup and Dependencies
- Mapping Fields
- Checking the Autocode Generation
- Integrating Title
- Mapping Values
- @Tests

This library helps to map fields between java POJOs creating code automatically for the mapper.

The code generation at compiling time requires maven plugins in order to allow the code generation.


Maven setup and Dependencies

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>11</source>
<target>11</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

Mapping Fields

Having to POJOs 

Customer
@Data
public class Customer {
private long id;
private String firstName;
private String lastName;
//private Title title;
private LocalDate dateOfBirth;
private BigDecimal creditScore;
private CustomerType customerType;
private Address address;
private Date creation;
}
CustomerDto
@Data
public class CustomerDto {
public long customerId;
public String firstName;
public String lastName;
public double creditScore;
public String dateOfBirth;
public LocalDate creation;
public String title;
public AddressDto address;
public String fullName;
}




Checking the auto code generation


@Mapper
public interface CustomerMapper {
}

When compile is generated the class CustomerMapperImpl in target.generated-sources in this case not map anything because nothing has been coded in CustomerMapper

import javax.annotation.processing.Generated;

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-24T10:57:51-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class CustomerMapperImpl implements CustomerMapper {
}
Lets code the map function in the mapper

@Mapper
public interface CustomerMapper {

CustomerDto customerToDto(Customer customer);

}
When compile the code generates the CustomerMapperImpl, based on the name of the fields, mapstruct makes the necessary convertions between fields,  even creates the Address mapper. if mapStruct finds a field that does not know how to convert, MapStruct will indicate that a conversion is needed to be coded. The fields that has not the same name, must by indicated by @Mapping annotation specifyng the source field and the target field. 

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-24T11:53:23-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class CustomerMapperImpl implements CustomerMapper {

@Override
public CustomerDto customerToDto(Customer customer) {
if ( customer == null ) {
return null;
}

CustomerDto customerDto = new CustomerDto();

customerDto.setFirstName( customer.getFirstName() );
customerDto.setLastName( customer.getLastName() );
if ( customer.getCreditScore() != null ) {
customerDto.setCreditScore( customer.getCreditScore().doubleValue() );
}
if ( customer.getDateOfBirth() != null ) {
customerDto.setDateOfBirth( DateTimeFormatter.ISO_LOCAL_DATE.format( customer.getDateOfBirth() ) );
}
if ( customer.getCreation() != null ) {
customerDto.setCreation( LocalDateTime.ofInstant( customer.getCreation().toInstant(), ZoneOffset.UTC ).toLocalDate() );
}
customerDto.setAddress( addressToAddressDto( customer.getAddress() ) );

return customerDto;
}

protected AddressDto addressToAddressDto(Address address) {
if ( address == null ) {
return null;
}

AddressDto addressDto = new AddressDto();

addressDto.setStreet( address.getStreet() );
addressDto.setCity( address.getCity() );

return addressDto;
}
}
Also, to avoid bolierplate of the addressMapper generated into the CustomerMapper, just specifying to the use existing AddressMapper  


@Mapper(uses=AddressMapper.class)
public interface CustomerMapper {

@Mapping(target = "customerId", source = "id")
@Mapping(target = "dateOfBirth", dateFormat = "dd.MM.yyyy")
@Mapping(target = "fullName", expression = "java(customer.getFirstName() + \" \" + customer.getLastName())")
CustomerDto customerToDto(Customer customer);

default String toString(Title title){
return title.getName();
}
}
The generated CustomerMapperImpl now includes the id, fullName , format the date, and use the AddressMapper.

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-24T12:17:58-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
public class CustomerMapperImpl implements CustomerMapper {

private final AddressMapper addressMapper = Mappers.getMapper( AddressMapper.class );

@Override
public CustomerDto customerToDto(Customer customer) {
if ( customer == null ) {
return null;
}

CustomerDto customerDto = new CustomerDto();

customerDto.setCustomerId( customer.getId() );
if ( customer.getDateOfBirth() != null ) {
customerDto.setDateOfBirth( DateTimeFormatter.ofPattern( "dd.MM.yyyy" ).format( customer.getDateOfBirth() ) );
}
customerDto.setFirstName( customer.getFirstName() );
customerDto.setLastName( customer.getLastName() );
if ( customer.getCreditScore() != null ) {
customerDto.setCreditScore( customer.getCreditScore().doubleValue() );
}
if ( customer.getCreation() != null ) {
customerDto.setCreation( LocalDateTime.ofInstant( customer.getCreation().toInstant(), ZoneOffset.UTC ).toLocalDate() );
}
customerDto.setAddress( addressMapper.addressToDto( customer.getAddress() ) );

customerDto.setFullName( customer.getFirstName() + " " + customer.getLastName() );

return customerDto;
}
}
Notice that the addressMapper instantiation is made with Mappers.getMapper( AddressMapper.class)
if in the @Mapper is specifyed the componentModel ="spring" then addressMapper will be injected with @Autowired

Mapper with componentModel specyfied

@Mapper(uses=AddressMapper.class, componentModel = "spring")
public interface CustomerMapper {
... }
Generated with @Autowired
@Component
public class CustomerMapperImpl implements CustomerMapper {

@Autowired
private AddressMapper addressMapper;


 Integrating Title


CustomerMapper uses TitleMapper to map Title.String to String

@Mapper( uses=TitleMapper.class, componentModel = "spring")
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);

@Mapping(target = "customerId", source = "id")
@Mapping(target = "dateOfBirth", dateFormat = "dd.MM.yyyy")
@Mapping(target = "fullName", expression = "java(customer.getFirstName() + \" \" + customer.getLastName())")
CustomerDto customerToDto(Customer customer);

@Mapping(target = "id", source = "customerId")
@Mapping(target = "dateOfBirth", dateFormat = "dd.MM.yyyy")
Customer customerDtoToCustomer(CustomerDto customerDto);

default String toString(Title title){
return title.getName();
}
}
Uses TitleMapper

@Mapper
public interface TitleMapper {
@Mapping( source="title", target = "name")
Title strTitleToTitle(String title);
}
Code Generated


@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-26T19:07:18-0500",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.8 (Oracle Corporation)"
)
@Component
public class CustomerMapperImpl implements CustomerMapper {

@Autowired
private TitleMapper titleMapper;

@Override
public CustomerDto customerToDto(Customer customer) {
if ( customer == null ) {
return null;
}

CustomerDto customerDto = new CustomerDto();

customerDto.setCustomerId( customer.getId() );
if ( customer.getDateOfBirth() != null ) {
customerDto.setDateOfBirth( DateTimeFormatter.ofPattern( "dd.MM.yyyy" ).format( customer.getDateOfBirth() ) );
}
if ( customer.getCreditScore() != null ) {
customerDto.setCreditScore( customer.getCreditScore().doubleValue() );
}
if ( customer.getCreation() != null ) {
customerDto.setCreation( LocalDateTime.ofInstant( customer.getCreation().toInstant(), ZoneOffset.UTC ).toLocalDate() );
}
customerDto.setTitle( toString( customer.getTitle() ) );
customerDto.setAddress( addressToAddressDto( customer.getAddress() ) );

customerDto.setFullName( customer.getFirstName() + " " + customer.getLastName() );

return customerDto;
}

@Override
public Customer customerDtoToCustomer(CustomerDto customerDto) {
if ( customerDto == null ) {
return null;
}

Customer customer = new Customer();

customer.setId( customerDto.getCustomerId() );
if ( customerDto.getDateOfBirth() != null ) {
customer.setDateOfBirth( LocalDate.parse( customerDto.getDateOfBirth(), DateTimeFormatter.ofPattern( "dd.MM.yyyy" ) ) );
}
customer.setTitle( titleMapper.strTitleToTitle( customerDto.getTitle() ) );
customer.setCreditScore( BigDecimal.valueOf( customerDto.getCreditScore() ) );
customer.setAddress( addressDtoToAddress( customerDto.getAddress() ) );
if ( customerDto.getCreation() != null ) {
customer.setCreation( Date.from( customerDto.getCreation().atStartOfDay( ZoneOffset.UTC ).toInstant() ) );
}

return customer;
}

protected AddressDto addressToAddressDto(Address address) {
if ( address == null ) {
return null;
}

AddressDto addressDto = new AddressDto();

addressDto.setStreet( address.getStreet() );
addressDto.setCity( address.getCity() );

return addressDto;
}

protected Address addressDtoToAddress(AddressDto addressDto) {
if ( addressDto == null ) {
return null;
}

Address address = new Address();

address.setCity( addressDto.getCity() );
address.setStreet( addressDto.getStreet() );

return address;
}
}

Mapping Values


Defaul Value

@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

@Mapping(source = "fuelType", target="fuelType",defaultValue = "ELECTRIC")
CarDto carTOCarDto(Car car);
}

Mapping enum to enum types


Also a mapping of enum values can be done with mapStruct.


@Mapper(componentModel = "spring")
public interface StuffMapper {
StuffMapper INSTANCE = Mappers.getMapper( StuffMapper.class);

@ValueMappings({
@ValueMapping(source="CORROSIVE", target="POINTY"),
@ValueMapping(source="STICKY", target="SHORT"),
@ValueMapping(source="SALTY", target="FLAT"),
@ValueMapping(source= MappingConstants.ANY_REMAINING, target="LONG"),
@ValueMapping(source=MappingConstants.NULL, target="GREASY"),
})
public FurType slimeToFur(SlimeType slime);

@Mapping(source = "slimeType", target ="furtype" )
public FurryStuff slimyToFurry(SlimyStuff slimy);
}

With this example of mapping in @ValueMappings are mapped the correspondence of values. when null then GREASY value is assigned. When ANY REMAINING value on the source enum then the target will be LONG.

@Tests


The @Tests for StuffMapper using INSTANCE make the run faster than using @SpringBootTest in test class @Autowired to inject the mapper, and componentModel="spring" as parameter for @Mapper in the mapper. 


class StuffMapperTest {

@Test
void slimeToFurTest_CORROSIVE_to_POINTY() {
//given
SlimeType slime = SlimeType.CORROSIVE;
//when
FurType furType = StuffMapper.INSTANCE.slimeToFur( slime);
//then
Assertions.assertEquals(FurType.POINTY, furType);
}

@Test
void slimeToFurTest_NULL_to_GREASY() {
//given
SlimeType slime = null;
//when
FurType furType = StuffMapper.INSTANCE.slimeToFur( slime);
//then
Assertions.assertEquals(FurType.GREASY, furType);
}

@Test
void slimeToFurTest_ANYREMAINING_to_LONG() {
//given
SlimeType slime = SlimeType.SMELLY;
//when
FurType furType = StuffMapper.INSTANCE.slimeToFur( slime);
//then
Assertions.assertEquals(FurType.LONG, furType);
}

@Test
void slimyToFurryTest_CORROSIVE_to_POINTY() {
//given
SlimyStuff naOH = new SlimyStuff("NaOH", SlimeType.CORROSIVE);
//when
FurryStuff furryStuff = StuffMapper.INSTANCE.slimyToFurry(naOH);
//then
Assertions.assertEquals(FurType.POINTY, furryStuff.getFurtype());
}

@Test
void slimyToFurryTest_NULL_to_GREASY() {
//given
SlimyStuff naOH = new SlimyStuff("NaOH", null);
//when
FurryStuff furryStuff = StuffMapper.INSTANCE.slimyToFurry(naOH);
//then
Assertions.assertEquals(FurType.GREASY, furryStuff.getFurtype());
}

@Test
void slimyToFurryTest_ANYREMAINING_to_LONG() {
//given
SlimyStuff naOH = new SlimyStuff("NaOH", SlimeType.SMELLY);
//when
FurryStuff furryStuff = StuffMapper.INSTANCE.slimyToFurry(naOH);
//then
Assertions.assertEquals(FurType.LONG, furryStuff.getFurtype());
}
}

eot