In c# the library https://docs.automapper.org/en/stable/Getting-started.html exists. It allows us to specify all Mappers/Mappings in one File - MapStruct forces me to create a new interface for every Mapper, which results in a lot of files i have to create and clutters the project.
Is there any way to write these mappers in a way that they are all in one file at least, or that they can be configured programatically? I looked at alternatives like ModelMapper or JMaper, but they are not well maintained or way slower.
EDIT: i added sample code to illustrate the problem and highlight my issues with the current answer
public abstract class ProductMapper {
public abstract ProductDto convertToDto(Product Product);
public abstract Product convertToEntity(ProductDto checkoutProductDto);
public abstract List<ProductDto> convertToDtos(List<Product> entities);
public abstract List<Product> convertToEntities(List<ProductDto> dtos);
// below not working because of type erasure, so cant do it in the same file
public abstract List<ProductOrderDetails> convertToEntities(List<ProductOrderDetailsDto> entities);
My project has hundreds of DTOs, most of them just requiring these 4 methods and no AfterMapping. Making these by hand is a giant waste of time, are there any better approaches?
Edit: i got a better answer from the mapstruct devs: https://github.com/mapstruct/mapstruct/issues/3111
Creating an abstract class with the 4 base methods, but with generic types seems like it would solve the issue. You'd still need to create the interface manually but the 4 methods would be already defined.
Here's an example in kotlin of what I mean.
These classes and mappers ( I've used kotlin only for convenience, but the mappers are still generated in java ) :
package mapper
import org.mapstruct.Mapper
abstract class EntityMapper<A, B>() {
abstract fun toDto(a: A): B
abstract fun toEntity(b: B): A
}
data class Device(val id: String)
data class DeviceDto(val id: String)
@Mapper
abstract class DeviceMapper : EntityMapper<Device, DeviceDto>()
data class OtherDevice(val id: String)
data class OtherDeviceDto(val id: String)
@Mapper
abstract class OtherDeviceMapper : EntityMapper<OtherDevice, OtherDeviceDto>()
Make mapstruct generate these 2 following mappers:
@Component
public class DeviceMapperImpl extends DeviceMapper {
@Override
public DeviceDto toDto(Device a) {
if ( a == null ) {
return null;
}
String id = null;
id = a.getId();
DeviceDto deviceDto = new DeviceDto( id );
return deviceDto;
}
@Override
public Device toEntity(DeviceDto b) {
if ( b == null ) {
return null;
}
String id = null;
id = b.getId();
Device device = new Device( id );
return device;
}
}
And
@Component
public class OtherDeviceMapperImpl extends OtherDeviceMapper {
@Override
public OtherDeviceDto toDto(OtherDevice a) {
if ( a == null ) {
return null;
}
String id = null;
id = a.getId();
OtherDeviceDto otherDeviceDto = new OtherDeviceDto( id );
return otherDeviceDto;
}
@Override
public OtherDevice toEntity(OtherDeviceDto b) {
if ( b == null ) {
return null;
}
String id = null;
id = b.getId();
OtherDevice otherDevice = new OtherDevice( id );
return otherDevice;
}
}