mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-16 16:59:24 +00:00
6cd2d0353a
* update yaml frontmatter format * update abstract document * update abstract factory * use the new pattern template * acyclic visitor seo * adapter seo * ambassador seo * acl seo * aaa seo * async method invocation seo * balking seo * bridge seo * builder seo * business delegate and bytecode seo * caching seo * callback seo * chain seo * update headings * circuit breaker seo * client session + collecting parameter seo * collection pipeline seo * combinator SEO * command seo * cqrs seo * commander seo * component seo * composite seo * composite entity seo * composite view seo * context object seo * converter seo * crtp seo * currying seo * dao seo * data bus seo * data locality seo * data mapper seo * dto seo * decorator seo * delegation seo * di seo * dirty flag seo * domain model seo * double buffer seo * double checked locking seo * double dispatch seo * dynamic proxy seo * event aggregator seo * event-based asynchronous seo * eda seo * event queue seo * event sourcing seo * execute around seo * extension objects seo * facade seo * factory seo * factory kit seo * factory method seo * fanout/fanin seo * feature toggle seo * filterer seo * fluent interface seo * flux seo * flyweight seo * front controller seo * function composition seo * game loop seo * gateway seo * guarded suspension seo * half-sync/half-async seo * health check seo * hexagonal seo * identity map seo * intercepting filter seo * interpreter seo * iterator seo * layers seo * lazy loading seo * leader election seo * leader/followers seo * lockable object seo * rename and add seo for marker interface * master-worker seo * mediator seo * memento seo * metadata mapping seo * microservice aggregator seo * api gw seo * microservices log aggregration seo * mvc seo * mvi seo * mvp seo * mvvm seo * monad seo * monitor seo * monostate seo * multiton seo * mute idiom seo * naked objects & notification seo * null object seo * object mother seo * object pool seo * observer seo * optimistic locking seo * page controller seo * page object seo * parameter object seo * partial response seo * pipeline seo * poison pill seo * presentation model seo * private class data seo * producer-consumer seo * promise seo * property seo * prototype seo * proxy seo * queue-based load leveling seo * reactor seo * registry seo * repository seo * RAII seo * retry seo * role object seo * saga seo * separated interface seo * serialized entity seo * serialized lob seo * servant seo * server session seo * service layer seo * service locator seo * service to worker seo * sharding seo * single table inheritance seo * singleton seo * spatial partition seo * special case seo * specification seo * state seo * step builder seo * strangler seo * strategy seo * subclass sandbox seo * table module seo * template method seo * throttling seo * tolerant reader seo * trampoline seo * transaction script seo * twin seo * type object seo * unit of work seo * update method seo * value object seo * version number seo * virtual proxy seo * visitor seo * seo enhancements * seo improvements * SEO enhancements * SEO improvements * SEO additions * SEO improvements * more SEO improvements * rename hexagonal + SEO improvements * SEO improvements * more SEO stuff * SEO improvements * SEO optimizations * SEO enhancements * enchance SEO * improve SEO * SEO improvements * update headers
171 lines
7.7 KiB
Markdown
171 lines
7.7 KiB
Markdown
---
|
|
title: "Converter Pattern in Java: Streamlining Data Conversion Across Layers"
|
|
shortTitle: Converter
|
|
description: "Discover the benefits and implementation of the Converter Pattern in Java. Learn how to achieve seamless bidirectional conversion between different data formats, promoting clean code and flexibility in your applications."
|
|
category: Structural
|
|
language: en
|
|
tag:
|
|
- Compatibility
|
|
- Data transformation
|
|
- Decoupling
|
|
- Interface
|
|
- Object mapping
|
|
- Wrapping
|
|
---
|
|
|
|
## Also known as
|
|
|
|
* Mapper
|
|
* Translator
|
|
|
|
## Intent of Converter Design Pattern
|
|
|
|
The purpose of the Converter Pattern is to provide a generic, systematic way of bidirectional conversion between corresponding data types. This allows for a clean, decoupled implementation where types are unaware of each other. Additionally, the Converter pattern supports bidirectional collection mapping, minimizing boilerplate code.
|
|
|
|
## Detailed Explanation of Converter Pattern with Real-World Examples
|
|
|
|
Real-world example
|
|
|
|
> In a real-world scenario, consider a library system that interacts with a third-party book database. The library uses an internal book format, while the third-party database uses a different format. By employing the Converter Pattern, a converter class can transform the third-party book data into the library's format and vice versa. This ensures seamless integration without altering the internal structures of either system.
|
|
|
|
In plain words
|
|
|
|
> The Converter Pattern simplifies mapping instances of one class to instances of another class, ensuring consistent and clean data transformation.
|
|
|
|
## Programmatic Example of Converter Pattern in Java
|
|
|
|
In applications, it's common for the database layer to have entities that need mapping to DTOs (Data Transfer Objects) for business logic. This mapping often involves many classes, necessitating a generic solution.
|
|
|
|
We introduce a generic `Converter` class:
|
|
|
|
```java
|
|
public class Converter<T, U> {
|
|
|
|
private final Function<T, U> fromDto;
|
|
private final Function<U, T> fromEntity;
|
|
|
|
public Converter(final Function<T, U> fromDto, final Function<U, T> fromEntity) {
|
|
this.fromDto = fromDto;
|
|
this.fromEntity = fromEntity;
|
|
}
|
|
|
|
public final U convertFromDto(final T dto) {
|
|
return fromDto.apply(dto);
|
|
}
|
|
|
|
public final T convertFromEntity(final U entity) {
|
|
return fromEntity.apply(entity);
|
|
}
|
|
|
|
public final List<U> createFromDtos(final Collection<T> dtos) {
|
|
return dtos.stream().map(this::convertFromDto).collect(Collectors.toList());
|
|
}
|
|
|
|
public final List<T> createFromEntities(final Collection<U> entities) {
|
|
return entities.stream().map(this::convertFromEntity).collect(Collectors.toList());
|
|
}
|
|
}
|
|
```
|
|
|
|
Specialized converters inherit from this base class:
|
|
|
|
```java
|
|
public class UserConverter extends Converter<UserDto, User> {
|
|
|
|
public UserConverter() {
|
|
super(UserConverter::convertToEntity, UserConverter::convertToDto);
|
|
}
|
|
|
|
private static UserDto convertToDto(User user) {
|
|
return new UserDto(user.firstName(), user.lastName(), user.active(), user.userId());
|
|
}
|
|
|
|
private static User convertToEntity(UserDto dto) {
|
|
return new User(dto.firstName(), dto.lastName(), dto.active(), dto.email());
|
|
}
|
|
}
|
|
```
|
|
|
|
Mapping between `User` and `UserDto` becomes straightforward:
|
|
|
|
```java
|
|
public static void main(String[] args) {
|
|
Converter<UserDto, User> userConverter = new UserConverter();
|
|
|
|
UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
|
|
User user = userConverter.convertFromDto(dtoUser);
|
|
LOGGER.info("Entity converted from DTO: {}", user);
|
|
|
|
var users = List.of(
|
|
new User("Camile", "Tough", false, "124sad"),
|
|
new User("Marti", "Luther", true, "42309fd"),
|
|
new User("Kate", "Smith", true, "if0243")
|
|
);
|
|
LOGGER.info("Domain entities:");
|
|
users.stream().map(User::toString).forEach(LOGGER::info);
|
|
|
|
LOGGER.info("DTO entities converted from domain:");
|
|
List<UserDto> dtoEntities = userConverter.createFromEntities(users);
|
|
dtoEntities.stream().map(UserDto::toString).forEach(LOGGER::info);
|
|
}
|
|
```
|
|
|
|
Program output:
|
|
|
|
```
|
|
08:28:27.019 [main] INFO com.iluwatar.converter.App -- Entity converted from DTO: User[firstName=John, lastName=Doe, active=true, userId=whatever[at]wherever.com]
|
|
08:28:27.035 [main] INFO com.iluwatar.converter.App -- Domain entities:
|
|
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Camile, lastName=Tough, active=false, userId=124sad]
|
|
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Marti, lastName=Luther, active=true, userId=42309fd]
|
|
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Kate, lastName=Smith, active=true, userId=if0243]
|
|
08:28:27.036 [main] INFO com.iluwatar.converter.App -- DTO entities converted from domain:
|
|
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Camile, lastName=Tough, active=false, email=124sad]
|
|
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Marti, lastName=Luther, active=true, email=42309fd]
|
|
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Kate, lastName=Smith, active=true, email=if0243]
|
|
```
|
|
|
|
## When to Use the Converter Pattern in Java
|
|
|
|
Use the Converter Pattern in the following situations:
|
|
|
|
* When there are types that logically correspond with each other, and there is a need to convert between them.
|
|
* In applications that interact with external systems or services that require data in a specific format.
|
|
* For legacy systems integration where data models differ significantly from newer systems.
|
|
* When aiming to encapsulate conversion logic to promote single responsibility and cleaner code.
|
|
|
|
## Converter Pattern Java Tutorials
|
|
|
|
* [Converter Pattern in Java 8 (Boldare)](http://www.xsolve.pl/blog/converter-pattern-in-java-8/)
|
|
|
|
## Real-World Applications of Converter Pattern in Java
|
|
|
|
* Data Transfer Objects (DTOs) conversions in multi-layered applications.
|
|
* Adapting third-party data structures or API responses to internal models.
|
|
* ORM (Object-Relational Mapping) frameworks for mapping between database records and domain objects.
|
|
* Microservices architecture for data exchange between different services.
|
|
|
|
## Benefits and Trade-offs of Converter Pattern
|
|
|
|
Benefits:
|
|
|
|
* Separation of Concerns: Encapsulates conversion logic in a single component, keeping the rest of the application unaware of the conversion details.
|
|
* Reusability: Converter components can be reused across the application or even in different applications.
|
|
* Flexibility: Makes it easy to add new conversions without impacting existing code, adhering to the [Open/Closed Principle](https://java-design-patterns.com/principles/#open-closed-principle).
|
|
* Interoperability: Facilitates communication between different systems or application layers by translating data formats.
|
|
|
|
Trade-offs:
|
|
|
|
* Overhead: Introducing converters can add complexity and potential performance overhead, especially in systems with numerous data formats.
|
|
* Duplication: There's a risk of duplicating model definitions if not carefully managed, leading to increased maintenance.
|
|
|
|
## Related Java Design Patterns
|
|
|
|
* [Adapter](https://java-design-patterns.com/patterns/adapter/): Similar in intent to adapting interfaces, but Converter focuses on data models.
|
|
* [Facade](https://java-design-patterns.com/patterns/facade/): Provides a simplified interface to a complex system, which might involve data conversion.
|
|
* [Strategy](https://java-design-patterns.com/patterns/strategy/): Converters can use different strategies for conversion, especially when multiple formats are involved.
|
|
|
|
## References and Credits
|
|
|
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
|
|
* [Effective Java](https://amzn.to/4cGk2Jz)
|