Getting started with the DAMapping framework

This page will help you to get started with the DAMapping framework: install it, understand its principles, get started with basic usage and object tree mapping, integrate with dependency injection frameworks…

Basic usage of the framework

The class below is a Mapper as per DAMapping framework’s definition: it is a class with a method doing object mapping. It is identified by the @Mapper annotation.

@Mapper
public class FooToBar {
    public Bar map(Foo foo) {
        // some code returning a Bar instance
        // initialized/populated from the specified Foo instance
    }
}

Please note that this is a class, not an interface. We are not configuring a tool to do object mapping, we are providing object mapping code to the framework.

A class annotated with @Mapper is the atomic component of object mapping code according to DAMapping’s object mapping code paradigm. It is referred to as the “dedicated class”.

dedicated class can be implemented as enum, see the documentation

Although the example above is a dedicated class mapping a single type to another, the DAMapping framework does not enforce such a rule (though it is best to follow it), nor does it enforce any naming convention.

This is done on purpose as the goal of DAMapping is to support the developer, not to constrain him or her into a single way of coding.

1 class = 1 interface + 1 class

The first added value of the DAMapping framework is to save the developer from writing an interface and an implementing class for each mapper. They are generated by the framework at compile-time.

In the example above, the framework generates a FooToBarMapper interface and a FooToBarMapperImpl class (did you identify the naming pattern? ;-p).

The FooToBarMapper interface has a single method. Same name, same return type, same parameters and same annotations as the public method of the dedicated class. This interface is referred to as the “Mapper interface”.

public interface FooToBarMapper {
    Bar map(Foo foo);
}

The FooToBarMapperImpl class implements this method by instantiating a single instance of the dedicated class and delegating her the implementation of the method defined by FooToBarMapper. This class is referred to as the “MapperImpl class”.

public class FooToBarMapperImpl implements FooToBarMapper {
    private final FooToBar fooToBar = new FooToBar();
    @Override
    public Bar map(Foo foo) {
        return this.fooToBar.map(foo);
    }
}

Mapping object trees

The next added value of the DAMapping coding paradigm is to remove all the coding ceremony when mapping a object tree to another thanks to the DAMapping framework.

To map object trees, the developer composes generated Mapper interfaces into dedicated classes.

In the following example, the dedicated class AcmeToViten maps the type Acme to the type Viten. These types are the root of two (very simple) object trees: Acme has a property of type Foo which must be mapped to the Viten’s property of type Bar.

@Mapper
public class AcmeToViten {
    private final FooToBarMapper fooToBarMapper;
    public AcmeToViten(FooToBarMapper fooToBarMapper) {
        this.fooToBarMapper = fooToBarMapper;
    }
    public Viten map(Acme acme) {
        // some code instanciating a Viten instance and 
        // populating it from the specified Acme instance
        vilen.setBar(fooToBarMapper.map(acme.getFoo()));
        return vilen;
    }
}

The Mapper interface generated from this dedicated class has the same content as the FooToBarMapper interface.

The generated AcmeToVitenMapperImpl class is a little different from FooToBarMapperImpl as it defines a constructor with the same parameters and annotations as the dedicated class’s constructor.

public class AcmeToVitenMapperImpl implements AcmeToVitenMapper {
    private final AcmeToViten acmeToViten;
    public AcmeToVitenMapperImpl(FooToBarMapper fooToBarMapper) {
        this.acmeToViten = new AcmeToViten(fooToBarMapper);
    }
    @Override
    public Viten map(Acme acme) {
        return this.acmeToViten.map(acme);
    }
}

Integrating with DI frameworks

Obviously, few applications will instance concrete class directly. They will rather use a dependency-injection framework (Spring, Guice, Dagger, …) that will manage object instantiation and injection.

The DAMapping framework supports integrating with those frameworks, but as it is not a core functionality to writing object mapping code, we won’t go into too much details here.

The planned idea is to initially provide minimal support through the support of the JSR-330 specification (work in progress).

Next, extensive support for specific dependency-injection frameworks will be provided as plugins of DAMapping annotation processor.

Extensive support for Spring, for example, could be generating Configuration classes or XML configuration files or supporting Spring specific annotations.

Unit testing

I said earlier that the developer is not supposed to use the dedicated class directly.

It is exactly the opposite when it comes to unit testing. The developer must write unit tests againt the dedicated class directly. There is no point in testing DAMapping framework itself.

Note that thanks to DAMapping, the developer can write real unitary tests of the mapping from one type to another. Mapping of properties with complex types can be isolated in other dedicated classes and imported into the current one as Mapper interfaces, which can be easily mocked.