CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-dozermapper--dozer-core

Java Bean to Java Bean mapper that recursively copies data from one object to another

Pending
Overview
Eval results
Files

bean-factory.mddocs/

Bean Factory System

Custom object creation during mapping for advanced instantiation patterns, dependency injection integration, and specialized object construction scenarios.

Capabilities

Bean Factory Interface

Primary interface for custom object creation during mapping operations.

/**
 * Custom bean factory interface for creating destination objects during mapping
 */
public interface BeanFactory {
    /**
     * Creates a bean instance during mapping
     * @param source source object being mapped from
     * @param sourceClass source class type
     * @param targetBeanId target bean identifier from mapping configuration
     * @param beanContainer Dozer's bean container for additional context
     * @return created bean instance
     */
    default Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer);
    
    /**
     * Creates a bean instance during mapping (deprecated)
     * @param source source object being mapped from
     * @param sourceClass source class type
     * @param targetBeanId target bean identifier from mapping configuration
     * @return created bean instance
     * @deprecated Use createBean(Object, Class, String, BeanContainer) instead
     */
    @Deprecated
    default Object createBean(Object source, Class<?> sourceClass, String targetBeanId);
}

Bean Builder Interface

Interface for building bean instances with a builder pattern approach.

/**
 * Interface for building bean instances
 */
public interface BeanBuilder {
    /**
     * Gets the class type this builder creates
     * @return class type of beans created by this builder
     */
    Class<?> beanClass();
    
    /**
     * Builds and returns a new bean instance
     * @return constructed bean instance
     */
    Object build();
}

Bean Creation Strategy Interface

Strategy interface for general bean creation patterns.

/**
 * Strategy for general bean creation
 */
public interface BeanGeneralCreationStrategy {
    /**
     * Determines if this strategy can create the requested bean
     * @param directive bean creation directive containing creation requirements
     * @return true if this strategy can handle the creation, false otherwise
     */
    boolean isApplicable(BeanCreationDirective directive);
    
    /**
     * Creates the bean according to the directive
     * @param directive bean creation directive
     * @return created bean instance
     */
    Object create(BeanCreationDirective directive);
}

Bean Factory Implementation Examples

Spring Integration Factory

import org.springframework.context.ApplicationContext;
import com.github.dozermapper.core.BeanFactory;

public class SpringBeanFactory implements BeanFactory {
    private final ApplicationContext applicationContext;
    
    public SpringBeanFactory(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        if (targetBeanId != null && applicationContext.containsBean(targetBeanId)) {
            // Create bean by name from Spring context
            return applicationContext.getBean(targetBeanId);
        }
        
        // Fallback to create by type
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            return applicationContext.getBean(targetClass);
        } catch (Exception e) {
            throw new MappingException("Failed to create bean: " + targetBeanId, e);
        }
    }
}

CDI Integration Factory

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;

public class CDIBeanFactory implements BeanFactory {
    private final BeanManager beanManager;
    
    public CDIBeanFactory(BeanManager beanManager) {
        this.beanManager = beanManager;
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            Set<Bean<?>> beans = beanManager.getBeans(targetClass);
            
            if (beans.isEmpty()) {
                throw new MappingException("No CDI bean found for class: " + targetClass.getName());
            }
            
            Bean<?> bean = beanManager.resolve(beans);
            CreationalContext<?> context = beanManager.createCreationalContext(bean);
            
            return beanManager.getReference(bean, targetClass, context);
        } catch (ClassNotFoundException e) {
            throw new MappingException("Target class not found: " + targetBeanId, e);
        }
    }
}

Conditional Bean Factory

public class ConditionalBeanFactory implements BeanFactory {
    private final Map<String, BeanFactory> factoryMap;
    private final BeanFactory defaultFactory;
    
    public ConditionalBeanFactory(Map<String, BeanFactory> factoryMap, BeanFactory defaultFactory) {
        this.factoryMap = factoryMap;
        this.defaultFactory = defaultFactory;
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        // Choose factory based on source type or other conditions
        String factoryKey = determineFactoryKey(source, sourceClass, targetBeanId);
        
        BeanFactory factory = factoryMap.getOrDefault(factoryKey, defaultFactory);
        return factory.createBean(source, sourceClass, targetBeanId, beanContainer);
    }
    
    private String determineFactoryKey(Object source, Class<?> sourceClass, String targetBeanId) {
        // Business logic to determine which factory to use
        if (source instanceof DatabaseEntity) {
            return "database";
        } else if (source instanceof WebServiceResponse) {
            return "webservice";
        } else {
            return "default";
        }
    }
}

Builder Pattern Factory

public class BuilderPatternFactory implements BeanFactory {
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            
            // Look for builder pattern
            Method builderMethod = findBuilderMethod(targetClass);
            if (builderMethod != null) {
                Object builder = builderMethod.invoke(null);
                return callBuildMethod(builder);
            }
            
            // Fallback to default constructor
            return targetClass.getDeclaredConstructor().newInstance();
            
        } catch (Exception e) {
            throw new MappingException("Failed to create bean using builder pattern: " + targetBeanId, e);
        }
    }
    
    private Method findBuilderMethod(Class<?> targetClass) {
        try {
            // Look for common builder method names
            return targetClass.getMethod("builder");
        } catch (NoSuchMethodException e) {
            try {
                return targetClass.getMethod("newBuilder");
            } catch (NoSuchMethodException e2) {
                return null;
            }
        }
    }
    
    private Object callBuildMethod(Object builder) throws Exception {
        Method buildMethod = builder.getClass().getMethod("build");
        return buildMethod.invoke(builder);
    }
}

Source-Aware Factory

public class SourceAwareFactory implements BeanFactory {
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            
            // Create instance based on source data
            if (source instanceof User) {
                return createUserRelatedBean((User) source, targetClass);
            } else if (source instanceof Order) {
                return createOrderRelatedBean((Order) source, targetClass);
            }
            
            // Default creation
            return targetClass.getDeclaredConstructor().newInstance();
            
        } catch (Exception e) {
            throw new MappingException("Failed to create source-aware bean: " + targetBeanId, e);
        }
    }
    
    private Object createUserRelatedBean(User source, Class<?> targetClass) throws Exception {
        if (targetClass == UserProfileDto.class) {
            // Create with user-specific initialization
            UserProfileDto dto = new UserProfileDto();
            dto.setCreatedAt(Instant.now());
            dto.setLastModified(Instant.now());
            dto.setVersion(1);
            return dto;
        }
        
        return targetClass.getDeclaredConstructor().newInstance();
    }
    
    private Object createOrderRelatedBean(Order source, Class<?> targetClass) throws Exception {
        if (targetClass == OrderSummaryDto.class) {
            // Create with order-specific initialization
            OrderSummaryDto dto = new OrderSummaryDto();
            dto.setOrderDate(source.getCreatedDate());
            dto.setProcessingStatus("PENDING");
            return dto;
        }
        
        return targetClass.getDeclaredConstructor().newInstance();
    }
}

Bean Factory Registration

Single Factory Registration

Mapper mapper = DozerBeanMapperBuilder.create()
    .withBeanFactory("userFactory", new SpringBeanFactory(applicationContext))
    .build();

Multiple Factories Registration

Map<String, BeanFactory> factories = new HashMap<>();
factories.put("springFactory", new SpringBeanFactory(applicationContext));
factories.put("builderFactory", new BuilderPatternFactory());
factories.put("conditionalFactory", new ConditionalBeanFactory(factoryMap, defaultFactory));

Mapper mapper = DozerBeanMapperBuilder.create()
    .withBeanFactorys(factories)
    .build();

XML Configuration Integration

Mapping File with Bean Factory

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozermapper.github.io/schema/bean-mapping"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                              http://dozermapper.github.io/schema/bean-mapping.xsd">

    <mapping>
        <class-a>com.example.User</class-a>
        <class-b bean-factory="springFactory">com.example.UserDto</class-b>
        
        <field>
            <a>firstName</a>
            <b>fname</b>
        </field>
    </mapping>
    
    <mapping>
        <class-a>com.example.Order</class-a>
        <class-b bean-factory="builderFactory">com.example.OrderDto</class-b>
    </mapping>
    
</mappings>

Programmatic Configuration with Factory

public class FactoryMappingBuilder extends BeanMappingBuilder {
    @Override
    public void configure() {
        mapping(User.class, UserDto.class)
            .fields("firstName", "fname")
            .fields("lastName", "lname");
            
        // Configure destination type to use specific factory
        mapping(Order.class, type(OrderDto.class).beanFactory("orderFactory"))
            .fields("orderNumber", "number")
            .fields("totalAmount", "total");
    }
}

Advanced Bean Factory Patterns

Pooled Object Factory

public class PooledObjectFactory implements BeanFactory {
    private final Map<Class<?>, Queue<Object>> objectPools = new ConcurrentHashMap<>();
    private final int maxPoolSize;
    
    public PooledObjectFactory(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            
            // Try to get from pool first
            Queue<Object> pool = objectPools.get(targetClass);
            if (pool != null) {
                Object pooled = pool.poll();
                if (pooled != null) {
                    resetObject(pooled);
                    return pooled;
                }
            }
            
            // Create new instance if pool is empty
            return targetClass.getDeclaredConstructor().newInstance();
            
        } catch (Exception e) {
            throw new MappingException("Failed to create pooled bean: " + targetBeanId, e);
        }
    }
    
    public void returnToPool(Object obj) {
        Class<?> clazz = obj.getClass();
        Queue<Object> pool = objectPools.computeIfAbsent(clazz, k -> new ConcurrentLinkedQueue<>());
        
        if (pool.size() < maxPoolSize) {
            pool.offer(obj);
        }
    }
    
    private void resetObject(Object obj) {
        // Reset object state for reuse
        // Implementation depends on object structure
    }
}

Prototype-Based Factory

public class PrototypeFactory implements BeanFactory {
    private final Map<String, Object> prototypes = new ConcurrentHashMap<>();
    
    public void registerPrototype(String beanId, Object prototype) {
        prototypes.put(beanId, prototype);
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        Object prototype = prototypes.get(targetBeanId);
        if (prototype != null) {
            return clonePrototype(prototype);
        }
        
        // Fallback to class-based creation
        try {
            Class<?> targetClass = beanContainer.getClassLoader().loadClass(targetBeanId);
            return targetClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new MappingException("Failed to create bean from prototype: " + targetBeanId, e);
        }
    }
    
    private Object clonePrototype(Object prototype) {
        if (prototype instanceof Cloneable) {
            try {
                Method cloneMethod = prototype.getClass().getMethod("clone");
                cloneMethod.setAccessible(true);
                return cloneMethod.invoke(prototype);
            } catch (Exception e) {
                // Fall back to serialization cloning or other methods
            }
        }
        
        // Implement alternative cloning strategy
        return deepClone(prototype);
    }
    
    private Object deepClone(Object prototype) {
        // Implement deep cloning (serialization, reflection, etc.)
        return null; // Placeholder
    }
}

Error Handling

Factory Exception Handling

public class RobustBeanFactory implements BeanFactory {
    private final BeanFactory primaryFactory;
    private final BeanFactory fallbackFactory;
    private static final Logger logger = LoggerFactory.getLogger(RobustBeanFactory.class);
    
    public RobustBeanFactory(BeanFactory primaryFactory, BeanFactory fallbackFactory) {
        this.primaryFactory = primaryFactory;
        this.fallbackFactory = fallbackFactory;
    }
    
    @Override
    public Object createBean(Object source, Class<?> sourceClass, String targetBeanId, BeanContainer beanContainer) {
        try {
            return primaryFactory.createBean(source, sourceClass, targetBeanId, beanContainer);
        } catch (Exception e) {
            logger.warn("Primary factory failed for {}, trying fallback", targetBeanId, e);
            
            try {
                return fallbackFactory.createBean(source, sourceClass, targetBeanId, beanContainer);
            } catch (Exception fallbackException) {
                logger.error("Both primary and fallback factories failed for {}", targetBeanId, fallbackException);
                throw new MappingException("All factories failed to create bean: " + targetBeanId, fallbackException);
            }
        }
    }
}

Best Practices

Factory Design

  • Make factories stateless when possible for thread safety
  • Use factory method pattern for complex object creation
  • Implement proper error handling with meaningful exception messages

Performance Optimization

  • Cache expensive factory lookups and configurations
  • Consider object pooling for frequently created objects
  • Avoid heavy initialization in factory constructors

Integration Patterns

  • Use dependency injection containers (Spring, CDI) for complex scenarios
  • Implement factory chains for fallback behavior
  • Register factories during mapper initialization, not at runtime

Testing

  • Mock bean factories for unit testing mapping behavior
  • Test factory error scenarios and fallback mechanisms
  • Verify factory integration with dependency injection frameworks

Install with Tessl CLI

npx tessl i tessl/maven-com-github-dozermapper--dozer-core

docs

bean-factory.md

builder-configuration.md

core-mapping.md

custom-conversion.md

event-system.md

index.md

metadata-access.md

programmatic-mapping.md

tile.json