Skip to content

eschoysman/Mapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mapper


📦📦📦❗️❗️ This page is under construction ❗️❗️📦📦📦


Travis (.org) branch GitHub GitHub top language GitHub file size in bytes


Table of Contents


Prerequisites

The library is written in Java 8 with no external dependencies needed!


Let's code!

Just before looking to the first example, there is a little consideration to do: all destination classes of a mapping should have at least the empty public constructor, otherwise the Mapper will not be able to create a new instance to return. If the class cannot have such a constructor, see section "Customize the mapping" to find an alternative!

Now let's do some mappings!

Step 1 the first step is to create a Mapper instance that will contains all our wanted mappings:

Mapper mapper = new Mapper();

Step 2 once we have a mapper, we can define the mapping we want. To do that specify a Source class and a Destination class:

mapper.add(Source.class, Destination.class);    // create a mapping between Source and Destination types

Step 3 Once we have created a mapper and defined some mappings inside it (here from Source to Destination), we can map our objects:

Source src = /*creation of a Source istance*/;
Destination dest = mapper.map(src);   // mapping src object into Destination type

Full code

Mapper mapper = new Mapper();
mapper.add(Source.class, Destination.class);
Source src = /*creation of a Source istance*/;
Destination dest = mapper.map(src);

And that's all!


How does it work?

When the Mapper is build, it search automatically the field in the source type and in the destination type that are called with the same name and are of the same type (or if the source field can be assigned to the destination field).

But what happens if the needed mapping is between two variables with differents names, for example String name in the Source class and String user_name in the Destination class? There are different ways to do it, but the simplest is the following: use the @AliasNames annotation to the name field passing the destination field name. For example:

public class Source {
    // ...
    @AliasNames("user_name")
    private String name;
    // ...
}

We can also put the annotation to the destination field @AliasNames("name"), the result will be the same, or to both field (the same name inside the annotation): @AliasNames("friend_name")

For more customize mappings, see the "Customize the mapping" section.


Multiple mappings from/to the same type

In the Mapper, the identifier of a given mapping is the pair Source-Destination classes, so we can easily add all the mapping we want.

From the same type

First we add two different mapping from the Source class.

Mapper mapper = new Mapper();
mapper.add(Source.class, Destination1.class);
mapper.add(Source.class, Destination2.class);

To map a source instance, we can do as following:

Source src = /*creation of a Source istance*/;
Destination1 dest = mapper.map(src,Destination1.class);

In this case we have to specify the destination class otherwise the mapper will not able to determine the destination type of the required mapping! If the Source class has only one mapping, the destination class is not mandatory (mapper.map(src)).

To the same type

First we add two different mapping to the Destination class.

Mapper mapper = new Mapper();
mapper.add(Source1.class, Destination.class);
mapper.add(Source2.class, Destination.class);

Now we have a known situation (one source class for one destination class) and we already know how to manage it!

Source1 src1 = /*creation of a Source1 istance*/;
Source2 src2 = /*creation of a Source2 istance*/;
Destination dest1 = mapper.map(src1);
Destination dest2 = mapper.map(src2);

Mappings of multiple classes and complex objects

The example above shows the basic case of a Mapper with only one effective mapping inside. It's not rare to want to convert different object or complex object that have not only simple field such that String, int or similar, but also complex variables like ComplexSourceObject.

The solution is simply: add more mappings to the mapper.

For example the Source and Destination classes contains a complex object as below:

public class Source {
    // ...
    private ComplexSourceObject obj;
    // ...
}

public class Destination {
    // ...
    private ComplexDestinationObject obj;
    // ...
}

Our example code become:

Mapper mapper = new Mapper();
mapper.add(Source.class, Destination.class);
mapper.add(ComplexSourceObject.class, ComplexDestinationObject.class);
Source src = /*creation of a Source istance*/;
Destination dest = mapper.map(src);

Mapping collections and arrays

If the field to be mapped is a Collection or an array, the same logic of our previous examples still works. The default mapping will be created if both the field in the source class and the destination type are:

  • collection of the same type, or the source collection can be assign to the destination filed, and the inner type is the same or the source inner type is assignable to the destination inner type;
  • arrays witch inner type is the same or the source inner type is assignable to the destination inner type

For the collection, we often defined a field with an interface type (List or Set for example) that are not instanziable. To make the mapping work correclty, we can use the annotation CollectionType to specify the type of the sub-collection to be instantiate for the destination field:

public class Source {
    // ...
    @CollectionType(ArrayList.class)
    private List<String> name;
    // ...
}

For more customize mappings, see the "Customize the mapping" section.


Configuration

// TODO add description of the available configurations


Customize the mapping

So far we only saw how to create default mapping, but rarely is the mapping we want at the end: this library allow using 20.162 different ways to create a custom mapping!

// TODO


Logging

The library used to log is slf4j (Simple Logging Facade for Java, http://www.slf4j.org/) and this allows you to use the logger library you prefer.

The following libraries worked successfully:

  • SLF4J Simple
  • JUL (java.util.logging)
  • logback
  • log4j

// TODO


Spring

The Mapper class is annotated with @Component, so you can create a bean to autowired a Mapper instance to use inside your Spring project.

// TODO


In the future

  • support for generic in custom types

Download

With Maven:

First add a new repository inside your pom.xml

<repositories>
    <repository>
        <id>mvn-repo</id>
        <url>https://github.com/eschoysman/repository/raw/mvn-repo</url>
    </repository>
</repositories>

Next add the dependency to the artifact

<dependency>
    <groupId>io.github.eschoysman</groupId>
    <artifactId>mapper</artifactId>
    <version>[1.0.0,)</version>
</dependency> 

Without Maven:

You can download the jar to include into you project here.


Javadoc

You can find the full javadoc updated to the last version here.


License

The code in this project is licensed under MIT License.


[]: #

About

Library for mapping a java object to another

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages