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.

Programmer DD
Programmer DD
Programmer DD
Simplify Bean Mapping with MapStruct Spring Extensions and ConversionService

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaspringmapstructConversionServicebean-mapping
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.