Skip to content

Commit 6d1b1a2

Browse files
119 Improvement: Customize class name and bean name for ConverterRegistrationConfiguration (#121)
* 119 Improvement: Customize class name and bean name for ConverterRegistrationConfiguration Added a way to define custom class name for ConverterRegistrationConfiguration * 119 Improvement: Customize class name and bean name for ConverterRegistrationConfiguration Added a way to define custom class name for ConverterRegistrationConfiguration * 119 Improvement: Customize class name and bean name for ConverterRegistrationConfiguration Added a way to define custom class name for ConverterRegistrationConfiguration * 119 Improvement: Customize class name and bean name for ConverterRegistrationConfiguration Added documentation Fixed generated import element to have simple name instead of full name(uncovered by unit test) * reverted mistakenly committed change --------- Co-authored-by: denis.simonov <[email protected]>
1 parent de3ea53 commit 6d1b1a2

File tree

13 files changed

+326
-16
lines changed

13 files changed

+326
-16
lines changed

annotations/src/main/java/org/mapstruct/extensions/spring/SpringMapperConfig.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414
@Target(ElementType.TYPE)
1515
@Retention(RetentionPolicy.SOURCE)
1616
public @interface SpringMapperConfig {
17+
18+
String DEFAULT_CONVERSION_SERVICE_BEAN_NAME = "conversionService";
19+
String DEFAULT_ADAPTER_CLASS_NAME = "ConversionServiceAdapter";
20+
String DEFAULT_CONFIGURATION_CLASS_NAME = "ConverterRegistrationConfiguration";
21+
22+
/**
23+
* The class name for the generated Configuration class,
24+
* which is performing auto-registration of converters/mappers
25+
* to Spring's {@link org.springframework.core.convert.ConversionService}.
26+
*
27+
* @return The class name for the generated Configuration.
28+
*/
29+
String converterRegistrationConfigurationClassName() default DEFAULT_CONFIGURATION_CLASS_NAME;
30+
1731
/**
1832
* The package name for the generated Adapter between the MapStruct mappers and Spring's {@link
1933
* org.springframework.core.convert.ConversionService}. If omitted or empty, the package name will
@@ -29,15 +43,15 @@
2943
*
3044
* @return The class name for the generated Adapter.
3145
*/
32-
String conversionServiceAdapterClassName() default "ConversionServiceAdapter";
46+
String conversionServiceAdapterClassName() default DEFAULT_ADAPTER_CLASS_NAME;
3347

3448
/**
3549
* The bean name for the Spring {@link org.springframework.core.convert.ConversionService} to use.
3650
*
3751
* @return The bean name for the Spring {@link
3852
* org.springframework.core.convert.ConversionService}.
3953
*/
40-
String conversionServiceBeanName() default "";
54+
String conversionServiceBeanName() default DEFAULT_CONVERSION_SERVICE_BEAN_NAME;
4155

4256
/**
4357
* To set if the Lazy annotation will be added to the ConversionService's usage in the

docs/src/docs/asciidoc/chapter-3-mapper-as-converter.asciidoc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,70 @@ public class ConversionServiceAdapterIntegrationTest {
170170
----
171171
====
172172

173+
[[converterRegistrationConfigurationClassName]]
174+
=== Modifying the name for the generated converter registration configuration class
175+
176+
By default, the converter registration configuration class will have name `ConverterRegistrationConfiguration`.
177+
If you wish to change this, you can do so by setting the property `converterRegistrationConfigurationClassName`:
178+
179+
====
180+
[source,java,linenums]
181+
[subs="verbatim,attributes"]
182+
----
183+
@MapperConfig(componentModel = "spring")
184+
@SpringMapperConfig(
185+
converterRegistrationConfigurationClassName = "MyConfiguration",
186+
generateConverterScan = true)
187+
public interface MapstructConfig {}
188+
----
189+
====
190+
191+
This changes the generated class name to be the property's value:
192+
193+
====
194+
[source,java,linenums]
195+
[subs="verbatim,attributes"]
196+
----
197+
@Configuration
198+
class MyConfiguration {
199+
private final ConfigurableConversionService conversionService;
200+
201+
private final List<Converter<?, ?>> converters;
202+
203+
MyConfiguration(
204+
@Qualifier("conversionService") final ConfigurableConversionService conversionService,
205+
final List<Converter<?, ?>> converters) {
206+
this.conversionService = conversionService;
207+
this.converters = converters;
208+
}
209+
210+
@PostConstruct
211+
void registerConverters() {
212+
converters.forEach(conversionService::addConverter);
213+
}
214+
}
215+
----
216+
====
217+
218+
Also this changes reference to converter registration configuration class from generated ConverterScan class:
219+
220+
====
221+
[source,java,linenums]
222+
[subs="verbatim,attributes"]
223+
----
224+
@ComponentScan
225+
@Target(TYPE)
226+
@Import(MyConfiguration.class)
227+
@Documented
228+
@Retention(RUNTIME)
229+
@Repeatable(ConverterScans.class)
230+
public @interface ConverterScan {
231+
...
232+
}
233+
----
234+
====
235+
236+
173237
[[adapterMethodName]]
174238
=== Modifying the name for the generated adapter method
175239

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
dependencies {
2+
annotationProcessor project(":extensions")
3+
implementation projects.examples.model
4+
implementation projects.annotations
5+
6+
testImplementation libs.assertj
7+
testImplementation libs.bundles.junit.jupiter
8+
implementation libs.jsr250
9+
implementation libs.mapstruct.core
10+
annotationProcessor libs.mapstruct.processor
11+
implementation libs.spring.context
12+
implementation libs.spring.core
13+
testImplementation libs.spring.test
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import org.mapstruct.Mapper;
4+
import org.mapstruct.Mapping;
5+
import org.springframework.core.convert.converter.Converter;
6+
import org.mapstruct.extensions.spring.example.Car;
7+
import org.mapstruct.extensions.spring.example.CarDto;
8+
9+
@Mapper(config = MapperSpringConfig.class)
10+
public interface CarMapper extends Converter<Car, CarDto> {
11+
@Mapping(target = "seats", source = "seatConfiguration")
12+
CarDto convert(Car car);
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import org.mapstruct.MapperConfig;
4+
import org.mapstruct.extensions.spring.SpringMapperConfig;
5+
6+
@MapperConfig(componentModel = "spring", uses = ConversionServiceAdapter.class)
7+
@SpringMapperConfig(
8+
converterRegistrationConfigurationClassName = "MyConfiguration",
9+
generateConverterScan = true)
10+
public interface MapperSpringConfig {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import org.mapstruct.Mapper;
4+
import org.mapstruct.Mapping;
5+
import org.mapstruct.extensions.spring.example.SeatConfiguration;
6+
import org.mapstruct.extensions.spring.example.SeatConfigurationDto;
7+
import org.springframework.core.convert.converter.Converter;
8+
9+
@Mapper(config = MapperSpringConfig.class)
10+
public interface SeatConfigurationMapper extends Converter<SeatConfiguration, SeatConfigurationDto> {
11+
@Mapping(target = "seatCount", source = "numberOfSeats")
12+
@Mapping(target = "material", source = "seatMaterial")
13+
SeatConfigurationDto convert(SeatConfiguration seatConfiguration);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import org.mapstruct.Mapper;
4+
import org.mapstruct.extensions.spring.example.Wheel;
5+
import org.mapstruct.extensions.spring.example.WheelDto;
6+
import org.springframework.core.convert.converter.Converter;
7+
8+
@Mapper(config = MapperSpringConfig.class)
9+
public interface WheelMapper extends Converter<Wheel, WheelDto> {
10+
@Override
11+
WheelDto convert(Wheel source);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import java.util.List;
4+
import org.mapstruct.Mapper;
5+
import org.mapstruct.extensions.spring.example.WheelDto;
6+
import org.mapstruct.extensions.spring.example.Wheels;
7+
import org.springframework.core.convert.converter.Converter;
8+
9+
@Mapper(config = MapperSpringConfig.class)
10+
public interface WheelsDtoListMapper extends Converter<List<WheelDto>, Wheels> {
11+
@Override
12+
Wheels convert(List<WheelDto> source);
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.mapstruct.extensions.spring.example.customconfiguration;
2+
3+
import java.util.List;
4+
import org.mapstruct.Mapper;
5+
import org.mapstruct.extensions.spring.example.Wheel;
6+
import org.mapstruct.extensions.spring.example.WheelDto;
7+
import org.mapstruct.extensions.spring.example.Wheels;
8+
import org.springframework.core.convert.converter.Converter;
9+
10+
@Mapper(config = MapperSpringConfig.class, imports = Wheel.class)
11+
public interface WheelsMapper extends Converter<Wheels, List<WheelDto>> {
12+
@Override
13+
List<WheelDto> convert(Wheels source);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package org.mapstruct.extensions.spring.example;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.api.extension.ExtendWith;
5+
import org.mapstruct.extensions.spring.example.customconfiguration.ConversionServiceAdapter;
6+
import org.mapstruct.extensions.spring.example.customconfiguration.ConverterScan;
7+
import org.mapstruct.extensions.spring.example.customconfiguration.MapperSpringConfig;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.ComponentScan;
11+
import org.springframework.context.annotation.Configuration;
12+
import org.springframework.core.convert.ConversionService;
13+
import org.springframework.core.convert.TypeDescriptor;
14+
import org.springframework.core.convert.support.DefaultConversionService;
15+
import org.springframework.test.context.junit.jupiter.SpringExtension;
16+
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
import static org.assertj.core.api.BDDAssertions.then;
21+
import static org.mapstruct.extensions.spring.example.CarType.OTHER;
22+
import static org.mapstruct.extensions.spring.example.SeatMaterial.LEATHER;
23+
import static org.mapstruct.extensions.spring.example.WheelPosition.RIGHT_FRONT;
24+
25+
@ExtendWith(SpringExtension.class)
26+
public class ConversionServiceAdapterIntegrationTest {
27+
private static final String TEST_MAKE = "Volvo";
28+
private static final CarType TEST_CAR_TYPE = OTHER;
29+
private static final int TEST_NUMBER_OF_SEATS = 5;
30+
private static final SeatMaterial TEST_SEAT_MATERIAL = LEATHER;
31+
private static final int TEST_DIAMETER = 20;
32+
private static final WheelPosition TEST_WHEEL_POSITION = RIGHT_FRONT;
33+
34+
@Autowired
35+
private ConversionService conversionService;
36+
37+
@Configuration
38+
@ComponentScan("org.mapstruct.extensions.spring.example.customconfiguration")
39+
static class ScanConfiguration {
40+
@Bean
41+
public ConversionService conversionService() {
42+
return new DefaultConversionService();
43+
}
44+
}
45+
46+
@Test
47+
void shouldKnowAllMappers() {
48+
then(conversionService.canConvert(Car.class, CarDto.class)).isTrue();
49+
then(conversionService.canConvert(SeatConfiguration.class, SeatConfigurationDto.class)).isTrue();
50+
then(conversionService.canConvert(Wheel.class, WheelDto.class)).isTrue();
51+
then(conversionService.canConvert(Wheels.class, List.class)).isTrue();
52+
then(conversionService.canConvert(List.class, Wheels.class)).isTrue();
53+
then(conversionService.canConvert(
54+
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(WheelDto.class)),
55+
TypeDescriptor.valueOf((Wheels.class))))
56+
.isTrue();
57+
}
58+
59+
@Test
60+
void shouldMapAllAttributes() {
61+
// Given
62+
final Car car = new Car();
63+
car.setMake(TEST_MAKE);
64+
car.setType(TEST_CAR_TYPE);
65+
final SeatConfiguration seatConfiguration = new SeatConfiguration();
66+
seatConfiguration.setSeatMaterial(TEST_SEAT_MATERIAL);
67+
seatConfiguration.setNumberOfSeats(TEST_NUMBER_OF_SEATS);
68+
car.setSeatConfiguration(seatConfiguration);
69+
final Wheels wheels = new Wheels();
70+
final ArrayList<Wheel> wheelsList = new ArrayList<>();
71+
final Wheel wheel = new Wheel();
72+
wheel.setDiameter(TEST_DIAMETER);
73+
wheel.setPosition(TEST_WHEEL_POSITION);
74+
wheelsList.add(wheel);
75+
wheels.setWheelsList(wheelsList);
76+
car.setWheels(wheels);
77+
78+
// When
79+
final CarDto mappedCar = conversionService.convert(car, CarDto.class);
80+
81+
// Then
82+
then(mappedCar).isNotNull();
83+
then(mappedCar.getMake()).isEqualTo(TEST_MAKE);
84+
then(mappedCar.getType()).isEqualTo(String.valueOf(TEST_CAR_TYPE));
85+
final SeatConfigurationDto mappedCarSeats = mappedCar.getSeats();
86+
then(mappedCarSeats).isNotNull();
87+
then(mappedCarSeats.getSeatCount()).isEqualTo(TEST_NUMBER_OF_SEATS);
88+
then(mappedCarSeats.getMaterial()).isEqualTo(String.valueOf(TEST_SEAT_MATERIAL));
89+
final WheelDto expectedWheelDto = new WheelDto();
90+
expectedWheelDto.setPosition(String.valueOf(TEST_WHEEL_POSITION));
91+
expectedWheelDto.setDiameter(TEST_DIAMETER);
92+
then(mappedCar.getWheels()).hasSize(1).containsExactly(expectedWheelDto);
93+
}
94+
95+
@Test
96+
void shouldMapGenericSourceType() {
97+
// Given
98+
final WheelDto dto = new WheelDto();
99+
dto.setPosition(String.valueOf(TEST_WHEEL_POSITION));
100+
dto.setDiameter(TEST_DIAMETER);
101+
final List<WheelDto> dtoList = new ArrayList<>();
102+
dtoList.add(dto);
103+
104+
// When
105+
final Wheels convertedWheels = conversionService.convert(dtoList, Wheels.class);
106+
107+
// Then
108+
final Wheel expectedWheel = new Wheel();
109+
expectedWheel.setPosition(TEST_WHEEL_POSITION);
110+
expectedWheel.setDiameter(TEST_DIAMETER);
111+
then(convertedWheels).isNotNull().hasSize(1).containsExactly(expectedWheel);
112+
}
113+
}

0 commit comments

Comments
 (0)