Mapping mit Orika

Mapping mit Orika

1. Überblick

Orika ist ein Java Bean-Mapping-Framework, dasrecursively copies data from one object to another enthält. Es kann sehr nützlich sein, wenn Sie mehrschichtige Anwendungen entwickeln.

Beim Hin- und Herbewegen von Datenobjekten zwischen diesen Ebenen stellen wir häufig fest, dass Objekte von einer Instanz in eine andere konvertiert werden müssen, um verschiedene APIs zu unterstützen.

Einige Möglichkeiten, dies zu erreichen, sind:hard coding the copying logic or to implement bean mappers like Dozer. Es kann jedoch verwendet werden, um den Prozess der Zuordnung zwischen einer Objektebene und einer anderen zu vereinfachen.

Orikauses byte code generation to create fast mappers mit minimalem Overhead, wodurch es viel schneller ist als andere reflexionsbasierte Mapper wieDozer.

2. Einfaches Beispiel

Der grundlegende Eckpfeiler des Mapping-Frameworks ist die KlasseMapperFactory. Dies ist die Klasse, mit der wir Zuordnungen konfigurieren und die InstanzMapperFacadeabrufen, die die eigentliche Zuordnungsarbeit ausführt.

Wir erstellen einMapperFactory-Objekt wie folgt:

MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

Nehmen wir dann an, wir haben ein Quelldatenobjekt,Source.java, mit zwei Feldern:

public class Source {
    private String name;
    private int age;

    public Source(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // standard getters and setters
}

Und ein ähnliches Zieldatenobjekt,Dest.java:

public class Dest {
    private String name;
    private int age;

    public Dest(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // standard getters and setters
}

Dies ist die einfachste Art der Bean-Zuordnung mit Orika:

@Test
public void givenSrcAndDest_whenMaps_thenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class);
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Source src = new Source("example", 10);
    Dest dest = mapper.map(src, Dest.class);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

Wie wir beobachten können, haben wir einDest-Objekt mit identischen Feldern wieSource erstellt, einfach durch Zuordnung. Bidirektionale oder umgekehrte Zuordnung ist ebenfalls standardmäßig möglich:

@Test
public void givenSrcAndDest_whenMapsReverse_thenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).byDefault();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Dest src = new Dest("example", 10);
    Source dest = mapper.map(src, Source.class);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

3. Maven Setup

Um Orika Mapper in unseren Maven-Projekten verwenden zu können, müssen wir die Abhängigkeit vonorika-coreinpom.xml haben:


    ma.glasnost.orika
    orika-core
    1.4.6

Die neueste Version ist immerhere zu finden.

3. Arbeiten mitMapperFactory

Das allgemeine Muster der Zuordnung mit Orika besteht darin, einMapperFactory-Objekt zu erstellen, es zu konfigurieren, falls das Standardzuordnungsverhalten angepasst werden muss, einMapperFacade-Objekt daraus zu erhalten und schließlich die tatsächliche Zuordnung vorzunehmen.

Wir werden dieses Muster in all unseren Beispielen beobachten. In unserem ersten Beispiel wurde jedoch das Standardverhalten des Mapper ohne Änderungen von unserer Seite gezeigt.

3.1. DieBoundMapperFacade vsMapperFacade

Eine Sache zu beachten ist, dass wirBoundMapperFacade anstelle der StandardMapperFacade verwenden könnten, was ziemlich langsam ist. In diesen Fällen müssen wir ein bestimmtes Typenpaar zuordnen.

Unser erster Test würde also werden:

@Test
public void givenSrcAndDest_whenMapsUsingBoundMapper_thenCorrect() {
    BoundMapperFacade
      boundMapper = mapperFactory.getMapperFacade(Source.class, Dest.class);
    Source src = new Source("example", 10);
    Dest dest = boundMapper.map(src);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

DamitBoundMapperFacade bidirektional abgebildet werden kann, müssen wir jedoch explizit diemapReverse-Methode aufrufen und nicht die Map-Methode, die wir für den Fall der StandardMapperFacade betrachtet haben:

@Test
public void givenSrcAndDest_whenMapsUsingBoundMapperInReverse_thenCorrect() {
    BoundMapperFacade
      boundMapper = mapperFactory.getMapperFacade(Source.class, Dest.class);
    Dest src = new Dest("example", 10);
    Source dest = boundMapper.mapReverse(src);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

Andernfalls schlägt der Test fehl.

3.2. Feldzuordnungen konfigurieren

Die bisher betrachteten Beispiele betreffen Quell- und Zielklassen mit identischen Feldnamen. Dieser Unterabschnitt befasst sich mit dem Fall, dass zwischen beiden ein Unterschied besteht.

Betrachten Sie ein Quellobjekt,Person, mit drei Feldern, nämlichname,nickname undage:

public class Person {
    private String name;
    private String nickname;
    private int age;

    public Person(String name, String nickname, int age) {
        this.name = name;
        this.nickname = nickname;
        this.age = age;
    }

    // standard getters and setters
}

Dann hat eine andere Ebene der Anwendung ein ähnliches Objekt, das jedoch von einem französischen Programmierer geschrieben wurde. Nehmen wir an, das heißtPersonne, wobei die Feldernom,surnom undage den obigen drei entsprechen:

public class Personne {
    private String nom;
    private String surnom;
    private int age;

    public Personne(String nom, String surnom, int age) {
        this.nom = nom;
        this.surnom = surnom;
        this.age = age;
    }

    // standard getters and setters
}

Orika kann diese Unterschiede nicht automatisch beheben. Wir können aberClassMapBuilderAPI to register these unique mappings. verwenden

Wir haben es bereits verwendet, aber noch keine der leistungsstarken Funktionen genutzt. Die erste Zeile jedes unserer vorhergehenden Tests unter Verwendung der StandardwerteMapperFacade verwendeteClassMapBuilderAPI to register the two classes we wanted to map:

mapperFactory.classMap(Source.class, Dest.class);

Wir könnten auch alle Felder mit der Standardkonfiguration zuordnen, um es klarer zu machen:

mapperFactory.classMap(Source.class, Dest.class).byDefault()

Durch Hinzufügen des MethodenaufrufsbyDefault() konfigurieren wir bereits das Verhalten des Mappers mithilfe vonClassMapBuilderAPI.

Jetzt möchten wirPersonnePerson zuordnen können, also konfigurieren wir auch Feldzuordnungen auf dem Mapper mitClassMapBuilderAPI:

@Test
public void givenSrcAndDestWithDifferentFieldNames_whenMaps_thenCorrect() {
    mapperFactory.classMap(Personne.class, Person.class)
      .field("nom", "name").field("surnom", "nickname")
      .field("age", "age").register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Personne frenchPerson = new Personne("Claire", "cla", 25);
    Person englishPerson = mapper.map(frenchPerson, Person.class);

    assertEquals(englishPerson.getName(), frenchPerson.getNom());
    assertEquals(englishPerson.getNickname(), frenchPerson.getSurnom());
    assertEquals(englishPerson.getAge(), frenchPerson.getAge());
}

Vergessen Sie nicht, die API-Methoderegister()aufzurufen, um die Konfiguration beiMapperFactory zu registrieren.

Selbst wenn sich nur ein Feld unterscheidet, bedeutet dies, dass wir die Feldzuordnungen vonallexplizit registrieren müssen, einschließlichage, die in beiden Objekten gleich sind, da sonst das nicht registrierte Feld nicht zugeordnet wird und der Test dies tun würde Scheitern.

Dies wird bald langweilig,what if we only want to map one field out of 20. Müssen wir alle ihre Zuordnungen konfigurieren?

Nein, nicht, wenn wir den Mapper anweisen, die Standard-Mapping-Konfiguration zu verwenden, wenn wir kein Mapping explizit definiert haben:

mapperFactory.classMap(Personne.class, Person.class)
  .field("nom", "name").field("surnom", "nickname").byDefault().register();

Hier haben wir keine Zuordnung für das Feldagedefiniert, aber der Test wird trotzdem bestanden.

3.3. Ein Feld ausschließen

Angenommen, wir möchten dasnom-Feld vonPersonne von der Zuordnung ausschließen, sodass dasPerson-Objekt nur neue Werte für Felder erhält, die nicht ausgeschlossen sind:

@Test
public void givenSrcAndDest_whenCanExcludeField_thenCorrect() {
    mapperFactory.classMap(Personne.class, Person.class).exclude("nom")
      .field("surnom", "nickname").field("age", "age").register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Personne frenchPerson = new Personne("Claire", "cla", 25);
    Person englishPerson = mapper.map(frenchPerson, Person.class);

    assertEquals(null, englishPerson.getName());
    assertEquals(englishPerson.getNickname(), frenchPerson.getSurnom());
    assertEquals(englishPerson.getAge(), frenchPerson.getAge());
}

Beachten Sie, wie wir es in der Konfiguration vonMapperFactory ausschließen, und beachten Sie dann auch die erste Behauptung, bei der wir erwarten, dass der Wert vonname im ObjektPersonnull bleibt, as ein Ergebnis davon, dass es in der Zuordnung ausgeschlossen wird.

4. Sammlungszuordnung

Manchmal verfügt das Zielobjekt über eindeutige Attribute, während das Quellobjekt nur alle Eigenschaften in einer Auflistung verwaltet.

4.1. Listen und Arrays

Stellen Sie sich ein Quelldatenobjekt vor, das nur ein Feld enthält, eine Liste der Namen einer Person:

public class PersonNameList {
    private List nameList;

    public PersonNameList(List nameList) {
        this.nameList = nameList;
    }
}

Betrachten Sie nun unser Zieldatenobjekt, dasfirstName undlastName in separate Felder unterteilt:

public class PersonNameParts {
    private String firstName;
    private String lastName;

    public PersonNameParts(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Nehmen wir an, wir sind sehr sicher, dass es bei Index 0 immer diefirstName der Person und bei Index 1 immer ihrelastName gibt.

Mit Orika können wir mithilfe der Klammernotation auf Mitglieder einer Sammlung zugreifen:

@Test
public void givenSrcWithListAndDestWithPrimitiveAttributes_whenMaps_thenCorrect() {
    mapperFactory.classMap(PersonNameList.class, PersonNameParts.class)
      .field("nameList[0]", "firstName")
      .field("nameList[1]", "lastName").register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    List nameList = Arrays.asList(new String[] { "Sylvester", "Stallone" });
    PersonNameList src = new PersonNameList(nameList);
    PersonNameParts dest = mapper.map(src, PersonNameParts.class);

    assertEquals(dest.getFirstName(), "Sylvester");
    assertEquals(dest.getLastName(), "Stallone");
}

Selbst wenn wir anstelle vonPersonNameListPersonNameArray hätten, würde der gleiche Test für ein Array von Namen bestehen.

4.2. Maps

Angenommen, unser Quellobjekt hat eine Wertekarte. Wir wissen, dass diese Karte einen Schlüssel enthält,first, dessen WertfirstName einer Person in unserem Zielobjekt darstellt.

Ebenso wissen wir, dass es in derselben Karte einen anderen Schlüssel gibt,last, dessen WertlastName einer Person im Zielobjekt darstellt.

public class PersonNameMap {
    private Map nameMap;

    public PersonNameMap(Map nameMap) {
        this.nameMap = nameMap;
    }
}

Ähnlich wie im vorherigen Abschnitt verwenden wir die Klammernotation, übergeben jedoch anstelle eines Index den Schlüssel, dessen Wert dem angegebenen Zielfeld zugeordnet werden soll.

Orika akzeptiert zwei Methoden zum Abrufen des Schlüssels. Beide werden im folgenden Test dargestellt:

@Test
public void givenSrcWithMapAndDestWithPrimitiveAttributes_whenMaps_thenCorrect() {
    mapperFactory.classMap(PersonNameMap.class, PersonNameParts.class)
      .field("nameMap['first']", "firstName")
      .field("nameMap[\"last\"]", "lastName")
      .register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Map nameMap = new HashMap<>();
    nameMap.put("first", "Leornado");
    nameMap.put("last", "DiCaprio");
    PersonNameMap src = new PersonNameMap(nameMap);
    PersonNameParts dest = mapper.map(src, PersonNameParts.class);

    assertEquals(dest.getFirstName(), "Leornado");
    assertEquals(dest.getLastName(), "DiCaprio");
}

Wir können entweder einfache Anführungszeichen oder doppelte Anführungszeichen verwenden, müssen diese jedoch umgehen.

5. Verschachtelte Felder zuordnen

Nehmen Sie an, dass sich in unserem Quelldatenobjekt ein weiteres Datenübertragungsobjekt (DTO) befindet, das die Werte enthält, die wir zuordnen möchten.

public class PersonContainer {
    private Name name;

    public PersonContainer(Name name) {
        this.name = name;
    }
}
public class Name {
    private String firstName;
    private String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Um auf die Eigenschaften des verschachtelten DTO zugreifen und sie unserem Zielobjekt zuordnen zu können, verwenden wir die Punktnotation wie folgt:

@Test
public void givenSrcWithNestedFields_whenMaps_thenCorrect() {
    mapperFactory.classMap(PersonContainer.class, PersonNameParts.class)
      .field("name.firstName", "firstName")
      .field("name.lastName", "lastName").register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    PersonContainer src = new PersonContainer(new Name("Nick", "Canon"));
    PersonNameParts dest = mapper.map(src, PersonNameParts.class);

    assertEquals(dest.getFirstName(), "Nick");
    assertEquals(dest.getLastName(), "Canon");
}

6. Nullwerte zuordnen

In einigen Fällen möchten Sie möglicherweise steuern, ob Nullen zugeordnet oder ignoriert werden, wenn sie auftreten. Standardmäßig ordnet Orika bei Auftreten Nullwerte zu:

@Test
public void givenSrcWithNullField_whenMapsThenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).byDefault();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Source src = new Source(null, 10);
    Dest dest = mapper.map(src, Dest.class);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

Dieses Verhalten kann auf verschiedenen Ebenen angepasst werden, je nachdem, wie spezifisch wir sein möchten.

6.1. Globale Konfiguration

Wir können unseren Mapper so konfigurieren, dass Nullen zugeordnet oder auf globaler Ebene ignoriert werden, bevor die globalenMapperFactoryerstellt werden. Erinnern Sie sich, wie wir dieses Objekt in unserem ersten Beispiel erstellt haben? Dieses Mal fügen wir während des Erstellungsprozesses einen zusätzlichen Aufruf hinzu:

MapperFactory mapperFactory = new DefaultMapperFactory.Builder()
  .mapNulls(false).build();

Wir können einen Test durchführen, um zu bestätigen, dass tatsächlich keine Nullen zugeordnet werden:

@Test
public void givenSrcWithNullAndGlobalConfigForNoNull_whenFailsToMap_ThenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class);
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Source src = new Source(null, 10);
    Dest dest = new Dest("Clinton", 55);
    mapper.map(src, dest);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), "Clinton");
}

Standardmäßig werden Nullen zugeordnet. Dies bedeutet, dass selbst wenn ein Feldwert im Quellobjektnull beträgt und der Wert des entsprechenden Felds im Zielobjekt einen aussagekräftigen Wert hat, dieser überschrieben wird.

In unserem Fall wird das Zielfeld nicht überschrieben, wenn das entsprechende Quellfeld einen Wert vonnullhat.

6.2. Lokale Konfiguration

Die Zuordnung vonnull-Werten kann aufClassMapBuilder gesteuert werden, indemmapNulls(true|false) odermapNullsInReverse(true|false) zum Steuern der Zuordnung von Nullen in umgekehrter Richtung verwendet werden.

Wenn Sie diesen Wert für eineClassMapBuilder-Instanz festlegen, nehmen alle Feldzuordnungen, die auf demselbenClassMapBuilder erstellt wurden, nachdem der Wert festgelegt wurde, denselben Wert an.

Lassen Sie uns dies anhand eines Beispieltests veranschaulichen:

@Test
public void givenSrcWithNullAndLocalConfigForNoNull_whenFailsToMap_ThenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).field("age", "age")
      .mapNulls(false).field("name", "name").byDefault().register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Source src = new Source(null, 10);
    Dest dest = new Dest("Clinton", 55);
    mapper.map(src, dest);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), "Clinton");
}

Beachten Sie, wie wirmapNulls aufrufen, bevor Sie das Feldname registrieren. Dadurch werden alle Felder nach dem Aufruf vonmapNullsignoriert, wenn sie den Wertnullhaben.

Die bidirektionale Zuordnung akzeptiert auch zugeordnete Nullwerte:

@Test
public void givenDestWithNullReverseMappedToSource_whenMapsByDefault_thenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).byDefault();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Dest src = new Dest(null, 10);
    Source dest = new Source("Vin", 44);
    mapper.map(src, dest);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), src.getName());
}

Wir können dies auch verhindern, indem wirmapNullsInReverse aufrufen undfalse übergeben:

@Test
public void
  givenDestWithNullReverseMappedToSourceAndLocalConfigForNoNull_whenFailsToMap_thenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).field("age", "age")
      .mapNullsInReverse(false).field("name", "name").byDefault()
      .register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Dest src = new Dest(null, 10);
    Source dest = new Source("Vin", 44);
    mapper.map(src, dest);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), "Vin");
}

6.3. Konfiguration auf Feldebene

Wir können dies auf Feldebene mitfieldMap konfigurieren, wie folgt:

mapperFactory.classMap(Source.class, Dest.class).field("age", "age")
  .fieldMap("name", "name").mapNulls(false).add().byDefault().register();

In diesem Fall wirkt sich die Konfiguration nur auf das Feldnameaus, wie wir es auf Feldebene genannt haben:

@Test
public void givenSrcWithNullAndFieldLevelConfigForNoNull_whenFailsToMap_ThenCorrect() {
    mapperFactory.classMap(Source.class, Dest.class).field("age", "age")
      .fieldMap("name", "name").mapNulls(false).add().byDefault().register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    Source src = new Source(null, 10);
    Dest dest = new Dest("Clinton", 55);
    mapper.map(src, dest);

    assertEquals(dest.getAge(), src.getAge());
    assertEquals(dest.getName(), "Clinton");
}

7. Orika Custom Mapping

Bisher haben wir uns einfache benutzerdefinierte Zuordnungsbeispiele mitClassMapBuilderAPI. We shall still use the same API but customize our mapping using Orika’s CustomMapper class. angesehen

Angenommen, wir haben zwei Datenobjekte mit jeweils einem bestimmten Feld namensdtob, das das Datum und die Uhrzeit der Geburt einer Person darstellt.

Ein Datenobjekt repräsentiert diesen Wert alsdatetime String im folgenden ISO-Format:

2007-06-26T21:22:39Z

und der andere entspricht demlong-Typ im folgenden Unix-Zeitstempelformat:

1182882159000

Es ist klar, dass keine der bisher behandelten Anpassungen ausreicht, um während des Zuordnungsprozesses zwischen den beiden Formaten zu konvertieren. Nicht einmal der in Orika integrierte Konverter kann den Auftrag ausführen. Hier müssen wirCustomMapper schreiben, um die erforderliche Konvertierung während des Mappings durchzuführen.

Lassen Sie uns unser erstes Datenobjekt erstellen:

public class Person3 {
    private String name;
    private String dtob;

    public Person3(String name, String dtob) {
        this.name = name;
        this.dtob = dtob;
    }
}

dann unser zweites datenobjekt:

public class Personne3 {
    private String name;
    private long dtob;

    public Personne3(String name, long dtob) {
        this.name = name;
        this.dtob = dtob;
    }
}

Wir werden im Moment nicht beschriften, welche Quelle und welches Ziel ist, daCustomMapper es uns ermöglicht, bidirektionales Mapping zu ermöglichen.

Hier ist unsere konkrete Implementierung der abstrakten Klasse vonCustomMapper:

class PersonCustomMapper extends CustomMapper {

    @Override
    public void mapAtoB(Personne3 a, Person3 b, MappingContext context) {
        Date date = new Date(a.getDtob());
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        String isoDate = format.format(date);
        b.setDtob(isoDate);
    }

    @Override
    public void mapBtoA(Person3 b, Personne3 a, MappingContext context) {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        Date date = format.parse(b.getDtob());
        long timestamp = date.getTime();
        a.setDtob(timestamp);
    }
};

Beachten Sie, dass wir die MethodenmapAtoB undmapBtoA implementiert haben. Indem wir beides implementieren, ist unsere Mapping-Funktion bidirektional.

Each method exposes the data objects we are mapping and we take care of copying the field values from one to the other.

Dort schreiben wir den benutzerdefinierten Code, um die Quelldaten gemäß unseren Anforderungen zu bearbeiten, bevor wir sie in das Zielobjekt schreiben.

Führen Sie einen Test durch, um zu bestätigen, dass unser benutzerdefinierter Mapper funktioniert:

@Test
public void givenSrcAndDest_whenCustomMapperWorks_thenCorrect() {
    mapperFactory.classMap(Personne3.class, Person3.class)
      .customize(customMapper).register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    String dateTime = "2007-06-26T21:22:39Z";
    long timestamp = new Long("1182882159000");
    Personne3 personne3 = new Personne3("Leornardo", timestamp);
    Person3 person3 = mapper.map(personne3, Person3.class);

    assertEquals(person3.getDtob(), dateTime);
}

Beachten Sie, dass wir den benutzerdefinierten Mapper weiterhin überClassMapBuilderAPI, just like all other simple customizations. an Orikas Mapper übergeben

Wir können auch bestätigen, dass bidirektionale Zuordnung funktioniert:

@Test
public void givenSrcAndDest_whenCustomMapperWorksBidirectionally_thenCorrect() {
    mapperFactory.classMap(Personne3.class, Person3.class)
      .customize(customMapper).register();
    MapperFacade mapper = mapperFactory.getMapperFacade();
    String dateTime = "2007-06-26T21:22:39Z";
    long timestamp = new Long("1182882159000");
    Person3 person3 = new Person3("Leornardo", dateTime);
    Personne3 personne3 = mapper.map(person3, Personne3.class);

    assertEquals(person3.getDtob(), timestamp);
}

8. Fazit

In diesem Artikel haben wirexplored the most important features of the Orika mapping framework.

Es gibt definitiv fortgeschrittenere Funktionen, die uns viel mehr Kontrolle geben, aber in den meisten Anwendungsfällen werden die hier behandelten mehr als genug sein.

Den vollständigen Projektcode und alle Beispiele finden Sie in meinengithub project. Vergessen Sie nicht, auch unser Tutorial zuDozer mapping frameworkzu lesen, da beide mehr oder weniger das gleiche Problem lösen.