0
# Bean Factory System
1
2
Custom object creation during mapping for advanced instantiation patterns, dependency injection integration, and specialized object construction scenarios.
3
4
## Capabilities
5
6
### Bean Factory Interface
7
8
Primary interface for custom object creation during mapping operations.
9
10
```java { .api }
11
/**
12
* Custom bean factory interface for creating destination objects during mapping
13
*/
14
public interface BeanFactory {
15
/**
16
* Creates a bean instance during mapping
17
* @param source source object being mapped from
18
* @param sourceClass source class type
19
* @param targetBeanId target bean identifier from mapping configuration
20
* @param beanContainer Dozer's bean container for additional context
21
* @return created bean instance
22
*/
23
default Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer);
24
25
/**
26
* Creates a bean instance during mapping (deprecated)
27
* @param source source object being mapped from
28
* @param sourceClass source class type
29
* @param targetBeanId target bean identifier from mapping configuration
30
* @return created bean instance
31
* @deprecated Use createBean(Object, Class, String, BeanContainer) instead
32
*/
33
@Deprecated
34
default Object createBean(Object source, Class<?> sourceClass, String targetBeanId);
35
}
36
```
37
38
### Bean Builder Interface
39
40
Interface for building bean instances with a builder pattern approach.
41
42
```java { .api }
43
/**
44
* Interface for building bean instances
45
*/
46
public interface BeanBuilder {
47
/**
48
* Gets the class type this builder creates
49
* @return class type of beans created by this builder
50
*/
51
Class<?> beanClass();
52
53
/**
54
* Builds and returns a new bean instance
55
* @return constructed bean instance
56
*/
57
Object build();
58
}
59
```
60
61
### Bean Creation Strategy Interface
62
63
Strategy interface for general bean creation patterns.
64
65
```java { .api }
66
/**
67
* Strategy for general bean creation
68
*/
69
public interface BeanGeneralCreationStrategy {
70
/**
71
* Determines if this strategy can create the requested bean
72
* @param directive bean creation directive containing creation requirements
73
* @return true if this strategy can handle the creation, false otherwise
74
*/
75
boolean isApplicable(BeanCreationDirective directive);
76
77
/**
78
* Creates the bean according to the directive
79
* @param directive bean creation directive
80
* @return created bean instance
81
*/
82
Object create(BeanCreationDirective directive);
83
}
84
```
85
86
## Bean Factory Implementation Examples
87
88
### Spring Integration Factory
89
90
```java
91
import org.springframework.context.ApplicationContext;
92
import com.github.dozermapper.core.BeanFactory;
93
94
public class SpringBeanFactory implements BeanFactory {
95
private final ApplicationContext applicationContext;
96
97
public SpringBeanFactory(ApplicationContext applicationContext) {
98
this.applicationContext = applicationContext;
99
}
100
101
@Override
102
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
103
if (targetBeanId != null && applicationContext.containsBean(targetBeanId)) {
104
// Create bean by name from Spring context
105
return applicationContext.getBean(targetBeanId);
106
}
107
108
// Fallback to create by type
109
try {
110
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
111
return applicationContext.getBean(targetClass);
112
} catch (Exception e) {
113
throw new MappingException("Failed to create bean: " + targetBeanId, e);
114
}
115
}
116
}
117
```
118
119
### CDI Integration Factory
120
121
```java
122
import javax.enterprise.context.spi.CreationalContext;
123
import javax.enterprise.inject.spi.Bean;
124
import javax.enterprise.inject.spi.BeanManager;
125
126
public class CDIBeanFactory implements BeanFactory {
127
private final BeanManager beanManager;
128
129
public CDIBeanFactory(BeanManager beanManager) {
130
this.beanManager = beanManager;
131
}
132
133
@Override
134
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
135
try {
136
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
137
Set<Bean<?>> beans = beanManager.getBeans(targetClass);
138
139
if (beans.isEmpty()) {
140
throw new MappingException("No CDI bean found for class: " + targetClass.getName());
141
}
142
143
Bean<?> bean = beanManager.resolve(beans);
144
CreationalContext<?> context = beanManager.createCreationalContext(bean);
145
146
return beanManager.getReference(bean, targetClass, context);
147
} catch (ClassNotFoundException e) {
148
throw new MappingException("Target class not found: " + targetBeanId, e);
149
}
150
}
151
}
152
```
153
154
### Conditional Bean Factory
155
156
```java
157
public class ConditionalBeanFactory implements BeanFactory {
158
private final Map<String, BeanFactory> factoryMap;
159
private final BeanFactory defaultFactory;
160
161
public ConditionalBeanFactory(Map<String, BeanFactory> factoryMap, BeanFactory defaultFactory) {
162
this.factoryMap = factoryMap;
163
this.defaultFactory = defaultFactory;
164
}
165
166
@Override
167
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
168
// Choose factory based on source type or other conditions
169
String factoryKey = determineFactoryKey(source, sourceClass, targetBeanId);
170
171
BeanFactory factory = factoryMap.getOrDefault(factoryKey, defaultFactory);
172
return factory.createBean(source, sourceClass, targetBeanId, beanContainer);
173
}
174
175
private String determineFactoryKey(Object source, Class<?> sourceClass, String targetBeanId) {
176
// Business logic to determine which factory to use
177
if (source instanceof DatabaseEntity) {
178
return "database";
179
} else if (source instanceof WebServiceResponse) {
180
return "webservice";
181
} else {
182
return "default";
183
}
184
}
185
}
186
```
187
188
### Builder Pattern Factory
189
190
```java
191
public class BuilderPatternFactory implements BeanFactory {
192
193
@Override
194
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
195
try {
196
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
197
198
// Look for builder pattern
199
Method builderMethod = findBuilderMethod(targetClass);
200
if (builderMethod != null) {
201
Object builder = builderMethod.invoke(null);
202
return callBuildMethod(builder);
203
}
204
205
// Fallback to default constructor
206
return targetClass.getDeclaredConstructor().newInstance();
207
208
} catch (Exception e) {
209
throw new MappingException("Failed to create bean using builder pattern: " + targetBeanId, e);
210
}
211
}
212
213
private Method findBuilderMethod(Class<?> targetClass) {
214
try {
215
// Look for common builder method names
216
return targetClass.getMethod("builder");
217
} catch (NoSuchMethodException e) {
218
try {
219
return targetClass.getMethod("newBuilder");
220
} catch (NoSuchMethodException e2) {
221
return null;
222
}
223
}
224
}
225
226
private Object callBuildMethod(Object builder) throws Exception {
227
Method buildMethod = builder.getClass().getMethod("build");
228
return buildMethod.invoke(builder);
229
}
230
}
231
```
232
233
### Source-Aware Factory
234
235
```java
236
public class SourceAwareFactory implements BeanFactory {
237
238
@Override
239
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
240
try {
241
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
242
243
// Create instance based on source data
244
if (source instanceof User) {
245
return createUserRelatedBean((User) source, targetClass);
246
} else if (source instanceof Order) {
247
return createOrderRelatedBean((Order) source, targetClass);
248
}
249
250
// Default creation
251
return targetClass.getDeclaredConstructor().newInstance();
252
253
} catch (Exception e) {
254
throw new MappingException("Failed to create source-aware bean: " + targetBeanId, e);
255
}
256
}
257
258
private Object createUserRelatedBean(User source, Class<?> targetClass) throws Exception {
259
if (targetClass == UserProfileDto.class) {
260
// Create with user-specific initialization
261
UserProfileDto dto = new UserProfileDto();
262
dto.setCreatedAt(Instant.now());
263
dto.setLastModified(Instant.now());
264
dto.setVersion(1);
265
return dto;
266
}
267
268
return targetClass.getDeclaredConstructor().newInstance();
269
}
270
271
private Object createOrderRelatedBean(Order source, Class<?> targetClass) throws Exception {
272
if (targetClass == OrderSummaryDto.class) {
273
// Create with order-specific initialization
274
OrderSummaryDto dto = new OrderSummaryDto();
275
dto.setOrderDate(source.getCreatedDate());
276
dto.setProcessingStatus("PENDING");
277
return dto;
278
}
279
280
return targetClass.getDeclaredConstructor().newInstance();
281
}
282
}
283
```
284
285
## Bean Factory Registration
286
287
### Single Factory Registration
288
289
```java
290
Mapper mapper = DozerBeanMapperBuilder.create()
291
.withBeanFactory("userFactory", new SpringBeanFactory(applicationContext))
292
.build();
293
```
294
295
### Multiple Factories Registration
296
297
```java
298
Map<String, BeanFactory> factories = new HashMap<>();
299
factories.put("springFactory", new SpringBeanFactory(applicationContext));
300
factories.put("builderFactory", new BuilderPatternFactory());
301
factories.put("conditionalFactory", new ConditionalBeanFactory(factoryMap, defaultFactory));
302
303
Mapper mapper = DozerBeanMapperBuilder.create()
304
.withBeanFactorys(factories)
305
.build();
306
```
307
308
## XML Configuration Integration
309
310
### Mapping File with Bean Factory
311
312
```xml
313
<?xml version="1.0" encoding="UTF-8"?>
314
<mappings xmlns="http://dozermapper.github.io/schema/bean-mapping"
315
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
316
xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
317
http://dozermapper.github.io/schema/bean-mapping.xsd">
318
319
<mapping>
320
<class-a>com.example.User</class-a>
321
<class-b bean-factory="springFactory">com.example.UserDto</class-b>
322
323
<field>
324
<a>firstName</a>
325
<b>fname</b>
326
</field>
327
</mapping>
328
329
<mapping>
330
<class-a>com.example.Order</class-a>
331
<class-b bean-factory="builderFactory">com.example.OrderDto</class-b>
332
</mapping>
333
334
</mappings>
335
```
336
337
### Programmatic Configuration with Factory
338
339
```java
340
public class FactoryMappingBuilder extends BeanMappingBuilder {
341
@Override
342
public void configure() {
343
mapping(User.class, UserDto.class)
344
.fields("firstName", "fname")
345
.fields("lastName", "lname");
346
347
// Configure destination type to use specific factory
348
mapping(Order.class, type(OrderDto.class).beanFactory("orderFactory"))
349
.fields("orderNumber", "number")
350
.fields("totalAmount", "total");
351
}
352
}
353
```
354
355
## Advanced Bean Factory Patterns
356
357
### Pooled Object Factory
358
359
```java
360
public class PooledObjectFactory implements BeanFactory {
361
private final Map<Class<?>, Queue<Object>> objectPools = new ConcurrentHashMap<>();
362
private final int maxPoolSize;
363
364
public PooledObjectFactory(int maxPoolSize) {
365
this.maxPoolSize = maxPoolSize;
366
}
367
368
@Override
369
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
370
try {
371
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
372
373
// Try to get from pool first
374
Queue<Object> pool = objectPools.get(targetClass);
375
if (pool != null) {
376
Object pooled = pool.poll();
377
if (pooled != null) {
378
resetObject(pooled);
379
return pooled;
380
}
381
}
382
383
// Create new instance if pool is empty
384
return targetClass.getDeclaredConstructor().newInstance();
385
386
} catch (Exception e) {
387
throw new MappingException("Failed to create pooled bean: " + targetBeanId, e);
388
}
389
}
390
391
public void returnToPool(Object obj) {
392
Class<?> clazz = obj.getClass();
393
Queue<Object> pool = objectPools.computeIfAbsent(clazz, k -> new ConcurrentLinkedQueue<>());
394
395
if (pool.size() < maxPoolSize) {
396
pool.offer(obj);
397
}
398
}
399
400
private void resetObject(Object obj) {
401
// Reset object state for reuse
402
// Implementation depends on object structure
403
}
404
}
405
```
406
407
### Prototype-Based Factory
408
409
```java
410
public class PrototypeFactory implements BeanFactory {
411
private final Map<String, Object> prototypes = new ConcurrentHashMap<>();
412
413
public void registerPrototype(String beanId, Object prototype) {
414
prototypes.put(beanId, prototype);
415
}
416
417
@Override
418
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
419
Object prototype = prototypes.get(targetBeanId);
420
if (prototype != null) {
421
return clonePrototype(prototype);
422
}
423
424
// Fallback to class-based creation
425
try {
426
Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
427
return targetClass.getDeclaredConstructor().newInstance();
428
} catch (Exception e) {
429
throw new MappingException("Failed to create bean from prototype: " + targetBeanId, e);
430
}
431
}
432
433
private Object clonePrototype(Object prototype) {
434
if (prototype instanceof Cloneable) {
435
try {
436
Method cloneMethod = prototype.getClass().getMethod("clone");
437
cloneMethod.setAccessible(true);
438
return cloneMethod.invoke(prototype);
439
} catch (Exception e) {
440
// Fall back to serialization cloning or other methods
441
}
442
}
443
444
// Implement alternative cloning strategy
445
return deepClone(prototype);
446
}
447
448
private Object deepClone(Object prototype) {
449
// Implement deep cloning (serialization, reflection, etc.)
450
return null; // Placeholder
451
}
452
}
453
```
454
455
## Error Handling
456
457
### Factory Exception Handling
458
459
```java
460
public class RobustBeanFactory implements BeanFactory {
461
private final BeanFactory primaryFactory;
462
private final BeanFactory fallbackFactory;
463
private static final Logger logger = LoggerFactory.getLogger(RobustBeanFactory.class);
464
465
public RobustBeanFactory(BeanFactory primaryFactory, BeanFactory fallbackFactory) {
466
this.primaryFactory = primaryFactory;
467
this.fallbackFactory = fallbackFactory;
468
}
469
470
@Override
471
public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
472
try {
473
return primaryFactory.createBean(source, sourceClass, targetBeanId, beanContainer);
474
} catch (Exception e) {
475
logger.warn("Primary factory failed for {}, trying fallback", targetBeanId, e);
476
477
try {
478
return fallbackFactory.createBean(source, sourceClass, targetBeanId, beanContainer);
479
} catch (Exception fallbackException) {
480
logger.error("Both primary and fallback factories failed for {}", targetBeanId, fallbackException);
481
throw new MappingException("All factories failed to create bean: " + targetBeanId, fallbackException);
482
}
483
}
484
}
485
}
486
```
487
488
## Best Practices
489
490
### Factory Design
491
- Make factories stateless when possible for thread safety
492
- Use factory method pattern for complex object creation
493
- Implement proper error handling with meaningful exception messages
494
495
### Performance Optimization
496
- Cache expensive factory lookups and configurations
497
- Consider object pooling for frequently created objects
498
- Avoid heavy initialization in factory constructors
499
500
### Integration Patterns
501
- Use dependency injection containers (Spring, CDI) for complex scenarios
502
- Implement factory chains for fallback behavior
503
- Register factories during mapper initialization, not at runtime
504
505
### Testing
506
- Mock bean factories for unit testing mapping behavior
507
- Test factory error scenarios and fallback mechanisms
508
- Verify factory integration with dependency injection frameworks