F.M, Marc Le Bihan, Torben, peter8015

Mapping entity objects to domain interface

3

I have an interface in domain and two string infrastructure that represent that interface. the problem is, the interface cannot initiate in mapper class so I don't know how to map entity to domain in manual mapping. I started learning senior coding so I shouldn't use switch and should consider solid concepts. The codes I wrote:
OrderDiscount is an interface in domain

discountType, discountValue are in database. These feilds should map to orderDiscount

domain:

private Order(String id,
String customerId,
List items,
Money totalPrice,
OrderDiscount discount,
OrderStatus status,
LocalDateTime createdAt,
LocalDateTime updatedAt
)
public static Order create(String customerId,
List items,
OrderDiscount discount){

LocalDateTime now = LocalDateTime.now();

Money finalPrice = calculateFinalPrice(items, discount);

return new Order(
UUID.randomUUID().toString(),
customerId,
items,
finalPrice,
discount,
OrderStatus.PENDING,
now,
now);
}
public interface OrderDiscount {
Money applyTo(Money total);
OrderDiscountDetail getDetails();
DiscountType type();
}
public interface OrderDiscountFactory {
DiscountType supportedType();

OrderDiscount create(OrderDiscountDetail detail,Currency currency);
}
public final class FixedAmountDiscount implements OrderDiscount {

private final Money fixedAmountDiscount;

private FixedAmountDiscount(Money fixedAmountDiscount) {

if (fixedAmountDiscount == null) {
throw new IllegalArgumentException(
"Flat Discount cannot be null"
);
}

if (fixedAmountDiscount.getAmount().compareTo(BigDecimal.ZERO) factories;

public DiscountRegistry(List factories) {

this.factories =
factories.stream()
.collect(Collectors.toMap(
OrderDiscountFactory::supportedType,
Function.identity()));
}

public OrderDiscount create(OrderDiscountDetail detail, Currency currency) {

return factories
.get(detail.type())
.create(detail, currency);
}
}
public class FixedAmountDiscountFactory implements OrderDiscountFactory {
private final DiscountRegistry registry;

public FixedAmountDiscountFactory(DiscountRegistry registry) {
this.registry = registry;
}

@Override
public DiscountType supportedType() {
return DiscountType.FIXED_AMOUNT;
}

@Override
public OrderDiscount create(OrderDiscountDetail detail, Currency currency) {
return registry.create(detail, currency);
}
}

infrastructure/entity:

@Getter
@Enumerated(EnumType.STRING)
@Column(name = "discount_type", nullable = false, length = 30)
@NotNull(message = "discount type is required")
private DiscountType discountType = DiscountType.NONE;

@Getter
@Column(name = "discount_value", nullable = false, precision = 19, scale = 2)
@NotNull(message = "discount value is required")
private BigDecimal discountValue = BigDecimal.ZERO;

The orderMapper I wrote:

public class OrderMapper {

private final OrderDiscountFactory discountFactory;

public OrderMapper(OrderDiscountFactory discountFactory) {
this.discountFactory = discountFactory;
}

public static OrderEntity toEntity(Order order) {

OrderDiscountDetail discountDetail = order.getDiscount().getDetails();

OrderEntity entity = new OrderEntity(
order.getId(),
order.getCustomerId(),
order.getTotalPrice().getAmount(),
CurrencyMapper.toEntity(
order.getTotalPrice().getCurrency()
),
order.getStatus(),
discountDetail.type(),
discountDetail.value()
);
for (OrderItem orderItem : order.getItems()) {
entity.addItem(toItemEntity(orderItem));
}

return entity;
}

private static OrderItemEntity toItemEntity(OrderItem item) {
return new OrderItemEntity(
item.getProductId(),
item.getProductName(),
item.getQuantity(),
item.getPrice().getAmount(),
CurrencyMapper.toEntity(item.getPrice().getCurrency()));
}

public Order toDomain(OrderEntity entity) {

Currency currency = Currency.getInstance(entity.getCurrency());

Money money = Money.create(entity.getTotalAmount(), currency);

OrderDiscountDetail detail =
new OrderDiscountDetail(
entity.getDiscountType(),
entity.getDiscountValue()
);

OrderDiscount discount =
discountFactory.create(detail, currency);

List items = entity.getItems()
.stream()
.map(OrderItemMapper::toDomain)
.toList();

return Order.restore(
entity.getId(),
entity.getCustomerId(),
items,
money,
discount,
entity.getStatus(),
entity.getCreatedAt(),
entity.getUpdatedAt()
);
}

}

I found this mapper is bad because the mapper becomes domain-dependent. Please give me the enterprise level answer. I meanthe senior code.

edited Jun 22 at 18:08

Arianna Angeletti 118 1 silver badge11 bronze badges

asked Jun 22 at 11:56

F.M 551 2 gold badges9 silver badges22 bronze badges

5 0

I think the domain interface should remains pure. 'OrderDetail' belongs to Order domain:

public interface OrderDiscount {
Money applyTo(Money total);
DiscountType type();
}

answered Jun 22 at 15:29

peter8015 41 7 bronze badges

1 Comment

Start asking to get answers

Find the answer to your question by asking.