Simplify Bean Mapping with MapStruct Spring Extensions and ConversionService
This article introduces MapStruct’s new Spring extension, shows how to replace manual BeanUtil conversions with generated mappers, explains the Spring Converter interface, and demonstrates custom configuration and integration with ConversionService for seamless DTO/VO/PO transformations in Java backend projects.
Hello, I'm DD! I recently saw a post about the new MapStruct Spring plugin and decided to share it.
MapStruct is a code generator that uses Java's annotation‑processor mechanism to replace manual BeanUtil code for converting between DTO, VO, and PO objects.
@Mapper(componentModel = "spring")
public interface AreaMapping {
List<AreaInfoListVO> toVos(List<Area> areas);
}With just a few lines, a collection of PO objects can be transformed into a collection of VO objects.
// spring bean
@Autowired
AreaMapping areaMapping;
// source
List<Area> areas = …;
// target
List<AreaInfoListVO> vos = areaMapping.toVos(areas);Spring provides a Converter<S,T> functional interface that converts a source type S to a target type T, which aligns with MapStruct’s purpose.
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) {
Assert.notNull(after, "After Converter must not be null");
return (s) -> {
T initialResult = this.convert(s);
return initialResult != null ? after.convert(initialResult) : null;
};
}
}The MapStruct Spring Extensions plugin automatically registers any Mapper that also implements Converter with Spring’s ConversionService, allowing conversions via conversionService.convert(...).
@Mapper(componentModel = "spring")
public interface CarMapper extends Converter<Car, CarDto> {
@Mapping(target = "seats", source = "seatConfiguration")
CarDto convert(Car car);
} @Autowired
private ConversionService conversionService;
Car car = …;
CarDto carDto = conversionService.convert(car, CarDto.class);The plugin generates an adapter class (by default
org.mapstruct.extensions.spring.converter.ConversionServiceAdapter) that delegates to the registered ConversionService.
package org.mapstruct.extensions.spring.converter;
@Component
public class ConversionServiceAdapter {
private final ConversionService conversionService;
public ConversionServiceAdapter(@Lazy final ConversionService conversionService) {
this.conversionService = conversionService;
}
public CarDto mapCarToCarDto(final Car source) {
return (CarDto) this.conversionService.convert(source, CarDto.class);
}
}Customizing the Adapter
By default the generated adapter resides in org.mapstruct.extensions.spring.converter with the name ConversionServiceAdapter. You can change the package and class name with @SpringMapperConfig:
package cn.felord.mapstruct.config;
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
conversionServiceAdapterClassName = "MapStructConversionServiceAdapter")
public class MapperSpringConfig {}Specifying a ConversionService Bean
If multiple ConversionService beans exist, specify the desired one via the conversionServiceBeanName attribute of @SpringMapperConfig:
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
conversionServiceAdapterClassName = "MapStructConversionServiceAdapter",
conversionServiceBeanName = "myConversionService")
public class MapperSpringConfig {}Integrating Spring’s Built‑in Converters
Spring provides many internal Converter<S,T> implementations. You can expose them to MapStruct via the externalConversions attribute:
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(
externalConversions = @ExternalConversion(sourceType = String.class, targetType = Locale.class))
public interface MapstructConfig {}The generated adapter will contain a method like:
public Locale mapStringToLocale(final String source) {
return conversionService.convert(source, Locale.class);
}Summary
The mapstruct-spring-annotations module lets developers use Spring’s ConversionService to invoke MapStruct mappers without manually importing each Mapper, enabling loose coupling between mappers while preserving MapStruct’s compile‑time mapping capabilities.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
