0
# Advanced Features
1
2
Advanced mapping control mechanisms, conditional mapping, subclass mapping, and fine-grained control over the mapping process.
3
4
## Capabilities
5
6
### Subclass Mapping
7
8
Support for polymorphic mapping with automatic subclass detection and specialized mappings.
9
10
```java { .api }
11
/**
12
* Configures the mapping to handle inheritance hierarchies.
13
*/
14
@Repeatable(SubclassMappings.class)
15
@Target(ElementType.METHOD)
16
@Retention(RetentionPolicy.CLASS)
17
@interface SubclassMapping {
18
/** Source subclass */
19
Class<?> source();
20
21
/** Target subclass */
22
Class<?> target();
23
24
/** Qualifiers for subclass mapping method selection */
25
Class<? extends Annotation>[] qualifiedBy() default {};
26
27
/** String-based qualifiers for subclass mapping method selection */
28
String[] qualifiedByName() default {};
29
}
30
31
/**
32
* Container for multiple @SubclassMapping annotations.
33
*/
34
@Target(ElementType.METHOD)
35
@Retention(RetentionPolicy.CLASS)
36
@interface SubclassMappings {
37
SubclassMapping[] value();
38
}
39
```
40
41
**Usage Examples:**
42
43
```java
44
// Inheritance hierarchy
45
public abstract class Vehicle {
46
private String brand;
47
private String model;
48
// getters, setters...
49
}
50
51
public class Car extends Vehicle {
52
private int doors;
53
private boolean convertible;
54
// getters, setters...
55
}
56
57
public class Motorcycle extends Vehicle {
58
private boolean hasSidecar;
59
private int engineSize;
60
// getters, setters...
61
}
62
63
// DTO hierarchy
64
public abstract class VehicleDto {
65
private String brand;
66
private String model;
67
// getters, setters...
68
}
69
70
public class CarDto extends VehicleDto {
71
private int doorCount;
72
private boolean isConvertible;
73
// getters, setters...
74
}
75
76
public class MotorcycleDto extends VehicleDto {
77
private boolean hasSidecar;
78
private String engineCapacity;
79
// getters, setters...
80
}
81
82
@Mapper
83
public interface VehicleMapper {
84
// Polymorphic mapping with subclass mappings
85
@SubclassMapping(source = Car.class, target = CarDto.class)
86
@SubclassMapping(source = Motorcycle.class, target = MotorcycleDto.class)
87
VehicleDto toVehicleDto(Vehicle vehicle);
88
89
// Specific subclass mappings
90
@Mapping(source = "doors", target = "doorCount")
91
@Mapping(source = "convertible", target = "isConvertible")
92
CarDto toCarDto(Car car);
93
94
@Mapping(source = "engineSize", target = "engineCapacity", numberFormat = "#,### cc")
95
MotorcycleDto toMotorcycleDto(Motorcycle motorcycle);
96
97
// Collection with subclass mapping
98
@SubclassMapping(source = Car.class, target = CarDto.class)
99
@SubclassMapping(source = Motorcycle.class, target = MotorcycleDto.class)
100
List<VehicleDto> toVehicleDtos(List<Vehicle> vehicles);
101
}
102
```
103
104
### Subclass Exhaustive Strategy
105
106
Strategy for handling missing subclass mappings.
107
108
```java { .api }
109
/**
110
* Strategy for handling missing implementation for super classes when using SubclassMapping.
111
*/
112
enum SubclassExhaustiveStrategy {
113
/** Generate compile error for missing subclass mappings */
114
COMPILE_ERROR,
115
116
/** Throw runtime exception for unmapped subclasses */
117
RUNTIME_EXCEPTION
118
}
119
```
120
121
**Usage Examples:**
122
123
```java
124
@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.COMPILE_ERROR)
125
public interface StrictVehicleMapper {
126
// Compiler will enforce all subclasses are mapped
127
@SubclassMapping(source = Car.class, target = CarDto.class)
128
@SubclassMapping(source = Motorcycle.class, target = MotorcycleDto.class)
129
// Missing Truck.class mapping will cause compile error
130
VehicleDto toVehicleDto(Vehicle vehicle);
131
132
CarDto toCarDto(Car car);
133
MotorcycleDto toMotorcycleDto(Motorcycle motorcycle);
134
// TruckDto toTruckDto(Truck truck); // Must be implemented
135
}
136
137
@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
138
public interface RuntimeVehicleMapper {
139
// Missing subclass mappings will throw runtime exception
140
@SubclassMapping(source = Car.class, target = CarDto.class)
141
VehicleDto toVehicleDto(Vehicle vehicle);
142
143
CarDto toCarDto(Car car);
144
// Mapping Motorcycle without SubclassMapping will throw exception at runtime
145
}
146
```
147
148
### Mapping Control Annotations
149
150
Fine-grained control over which mapping mechanisms are allowed.
151
152
```java { .api }
153
/**
154
* Meta-annotation to mark an annotation as a mapping control annotation.
155
*/
156
@Target(ElementType.ANNOTATION_TYPE)
157
@Retention(RetentionPolicy.CLASS)
158
@interface MappingControl {
159
/** Allowed mapping mechanisms */
160
MappingControl[] value() default {};
161
}
162
163
/**
164
* Enum defining the types of mapping mechanisms.
165
*/
166
enum MappingControl {
167
/** Direct assignment (no conversion) */
168
DIRECT,
169
170
/** Built-in type conversions */
171
BUILT_IN_CONVERSION,
172
173
/** User-defined mapping methods */
174
MAPPING_METHOD,
175
176
/** Complex mappings (multi-step conversions) */
177
COMPLEX_MAPPING
178
}
179
```
180
181
**Predefined Control Annotations:**
182
183
```java { .api }
184
/**
185
* Forces deep cloning by only allowing mapping methods.
186
*/
187
@MappingControl(MappingControl.MAPPING_METHOD)
188
@Target({ElementType.TYPE, ElementType.METHOD})
189
@Retention(RetentionPolicy.CLASS)
190
@interface DeepClone {
191
}
192
193
/**
194
* Disables complex mappings (multi-step transformations).
195
*/
196
@MappingControl({MappingControl.DIRECT, MappingControl.BUILT_IN_CONVERSION, MappingControl.MAPPING_METHOD})
197
@Target({ElementType.TYPE, ElementType.METHOD})
198
@Retention(RetentionPolicy.CLASS)
199
@interface NoComplexMapping {
200
}
201
202
/**
203
* Container for multiple @MappingControl annotations.
204
*/
205
@Target({ElementType.TYPE, ElementType.METHOD})
206
@Retention(RetentionPolicy.CLASS)
207
@interface MappingControls {
208
Class<? extends Annotation>[] value();
209
}
210
```
211
212
**Usage Examples:**
213
214
```java
215
// Deep cloning mapper - forces all mappings through methods
216
@Mapper
217
@DeepClone
218
public interface DeepCloneMapper {
219
PersonDto toPersonDto(Person person);
220
221
// All nested objects will be deeply cloned through mapping methods
222
OrderDto toOrderDto(Order order);
223
224
// Custom deep cloning method
225
AddressDto cloneAddress(Address address);
226
}
227
228
// No complex mapping - prevents multi-step conversions
229
@Mapper
230
public interface SimpleMapper {
231
@NoComplexMapping
232
@Mapping(source = "name", target = "fullName")
233
UserDto toUserDto(User user);
234
235
// Only direct assignments and built-in conversions allowed
236
ProductDto toProductDto(Product product);
237
}
238
239
// Custom mapping control
240
@MappingControl({MappingControl.DIRECT, MappingControl.MAPPING_METHOD})
241
@Target(ElementType.METHOD)
242
@Retention(RetentionPolicy.CLASS)
243
public @interface DirectOrCustomOnly {
244
}
245
246
@Mapper
247
public interface ControlledMapper {
248
@DirectOrCustomOnly
249
@Mapping(source = "value", target = "result")
250
ResultDto toResultDto(Source source);
251
252
// Custom method for controlled mapping
253
String transformValue(String input);
254
}
255
```
256
257
### Builder Pattern Support
258
259
Configuration for builder pattern integration in target objects.
260
261
```java { .api }
262
/**
263
* Configuration for builder pattern support.
264
*/
265
@Target({ElementType.TYPE, ElementType.METHOD})
266
@Retention(RetentionPolicy.CLASS)
267
@interface Builder {
268
/** Name of the build method */
269
String buildMethod() default "build";
270
271
/** Disable builder pattern */
272
boolean disableBuilder() default false;
273
}
274
```
275
276
**Usage Examples:**
277
278
```java
279
// Target class with builder
280
public class PersonDto {
281
private String name;
282
private int age;
283
private String email;
284
285
// Private constructor
286
private PersonDto(Builder builder) {
287
this.name = builder.name;
288
this.age = builder.age;
289
this.email = builder.email;
290
}
291
292
public static Builder builder() {
293
return new Builder();
294
}
295
296
public static class Builder {
297
private String name;
298
private int age;
299
private String email;
300
301
public Builder name(String name) {
302
this.name = name;
303
return this;
304
}
305
306
public Builder age(int age) {
307
this.age = age;
308
return this;
309
}
310
311
public Builder email(String email) {
312
this.email = email;
313
return this;
314
}
315
316
public PersonDto build() {
317
return new PersonDto(this);
318
}
319
}
320
321
// getters...
322
}
323
324
@Mapper
325
public interface BuilderMapper {
326
// Automatically uses builder pattern
327
PersonDto toPersonDto(Person person);
328
329
// Custom builder configuration
330
@Builder(buildMethod = "create")
331
CustomDto toCustomDto(Entity entity);
332
333
// Disable builder for specific mapping
334
@Builder(disableBuilder = true)
335
SimpleDto toSimpleDto(SimpleEntity entity);
336
}
337
```
338
339
### Annotation Processing Control
340
341
Control over generated code annotations and metadata.
342
343
```java { .api }
344
// Mapper configuration affecting generated code
345
@Mapper(
346
suppressTimestampInGenerated = true, // Remove timestamp from @Generated
347
implementationName = "Custom<CLASS_NAME>Impl", // Custom implementation name
348
implementationPackage = "com.example.generated" // Custom package
349
)
350
public interface ProcessingControlMapper {
351
PersonDto toPersonDto(Person person);
352
}
353
```
354
355
### Experimental Features
356
357
Access to experimental features that may change in future versions.
358
359
```java { .api }
360
/**
361
* Marks features as experimental and subject to change.
362
*/
363
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
364
@Retention(RetentionPolicy.CLASS)
365
@interface Experimental {
366
}
367
```
368
369
**Usage Examples:**
370
371
```java
372
@Mapper
373
public interface ExperimentalMapper {
374
@Experimental
375
@Mapping(target = "newField", expression = "java(experimentalTransform(source.getValue()))")
376
ExperimentalDto toExperimentalDto(Source source);
377
378
@Experimental
379
default String experimentalTransform(String input) {
380
// Experimental transformation logic
381
return input != null ? input.transform(String::toUpperCase) : null;
382
}
383
}
384
```
385
386
### Advanced Error Handling
387
388
Custom exception handling for mapping operations.
389
390
**Usage Examples:**
391
392
```java
393
@Mapper(unexpectedValueMappingException = MappingException.class)
394
public interface ErrorHandlingMapper {
395
// Custom exception for enum mapping errors
396
StatusDto mapStatus(Status status);
397
398
// Method-level exception override
399
@BeanMapping(unexpectedValueMappingException = ValidationException.class)
400
ValidatedDto toValidatedDto(Entity entity);
401
}
402
403
// Custom exceptions
404
public class MappingException extends RuntimeException {
405
public MappingException(String message) {
406
super(message);
407
}
408
}
409
410
public class ValidationException extends Exception {
411
public ValidationException(String message, Throwable cause) {
412
super(message, cause);
413
}
414
}
415
```
416
417
### Performance Optimizations
418
419
Advanced configuration for optimizing generated mapping code.
420
421
**Usage Examples:**
422
423
```java
424
@Mapper(
425
// Disable automatic sub-mapping generation for performance
426
disableSubMappingMethodsGeneration = true,
427
428
// Use constructor injection for better performance
429
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
430
431
// Strict null checking strategy
432
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS
433
)
434
public interface PerformanceMapper {
435
PersonDto toPersonDto(Person person);
436
437
// Explicit sub-mapping methods for control
438
AddressDto toAddressDto(Address address);
439
440
PhoneDto toPhoneDto(Phone phone);
441
}
442
```
443
444
### Integration with Validation Frameworks
445
446
Integration patterns with validation frameworks.
447
448
**Usage Examples:**
449
450
```java
451
@Mapper
452
public abstract class ValidatingMapper {
453
@Autowired
454
private Validator validator;
455
456
public PersonDto toPersonDto(Person person) {
457
PersonDto dto = mapPersonDto(person);
458
459
// Validate the result
460
Set<ConstraintViolation<PersonDto>> violations = validator.validate(dto);
461
if (!violations.isEmpty()) {
462
throw new ValidationException("Mapping validation failed: " + violations);
463
}
464
465
return dto;
466
}
467
468
@Mapping(source = "firstName", target = "name")
469
@Mapping(source = "birthDate", target = "dateOfBirth", dateFormat = "yyyy-MM-dd")
470
protected abstract PersonDto mapPersonDto(Person person);
471
472
@AfterMapping
473
protected void validateResult(@MappingTarget PersonDto dto) {
474
if (dto.getName() == null || dto.getName().trim().isEmpty()) {
475
throw new IllegalStateException("Name cannot be empty after mapping");
476
}
477
}
478
}
479
```