Assemblers

An assembler is an interface object responsible for mapping one or more aggregate(s) to a Data Transfer Object (DTO) and back.

In Domain-Driven Design an interface layer is necessary to avoid coupling your domain to the outside world. A domain object is never exposed directly to the outside world but is mapped to a Data Transfer Object specifically tailored for the client needs. The assembler pattern allows to encapsulate this mapping responsibility in a separate object.

Default assembler

Default assemblers are only available when you have at least one add-on providing a default assembler implementation, such as the ModelMapper add-on.

To have the business framework generate a default assembler, annotate your DTO class with @DtoOf:

@DtoOf(SomeAggregate.class)
public class SomeDto {
    
}

Then you can use a qualified injection of the parameterized Assembler interface. For ModelMapper, this would be:

public class SomeClass {
    @Inject
    private Assembler<SomeAggregate, SomeDto> someDtoAssembler;
    
    public void someMethod(SomeAggregate someAggregate) {
        SomeDto someDto = someDtoAssembler.createDtoFromAggregate(someAggregate);
    }
}

The example above maps the objects using default settings. See the ModelMapper add-on docs to learn about other possibilities.

Custom assembler

Sometimes it makes more sense to write your own custom assembler.

Declaration

To declare a custom assembler you have two alternatives:

Extend the BaseAssembler class:

public class SomeAssembler extends BaseAssembler<SomeAggregate, SomeDto> {
    @Override
    public void mergeAggregateIntoDto(A sourceAggregate, D targetDto) {
        // aggregate to dto mapping logic
    }

    @Override
    public void mergeDtoIntoAggregate(D sourceDto, A targetAggregate) {
        // dto to aggregate mapping logic
    }
}

Implement the Assembler interface:

public class SomeAssembler implements Assembler<SomeAggregate, SomeDto> {
    @Override
    public void mergeAggregateIntoDto(A sourceAggregate, D targetDto) {
        // aggregate to dto mapping logic
    }

    @Override
    public void mergeDtoIntoAggregate(D sourceDto, A targetAggregate) {
        // dto to aggregate mapping logic
    }

    @Override
    public Class<SomeDto> getDtoClass() {
        return SomeDto.class;
    }
}

Usage

To use your assembler directly, inject the Assembler interface:

public class SomeClass {
    @Inject
    private Assembler<SomeAggregate, SomeDto> someDtoAssembler;
    
    public void someMethod(SomeAggregate someAggregate) {
        SomeDto someDto = someDtoAssembler.createDtoFromAggregate(someAggregate);
    }
}

Read-on about fluent assembler DSL, which can automate advanced mapping operations with a one-liner.

   

On this page


Edit