• Link zu Xing
  • Link zu LinkedIn
  • Link zu X
  • Link zu Rss dieser Seite
  • Link zu GitHub
  • Newsletter
  • Kontaktieren Sie mich
Frank W. Rahn
  • Meine BlogbeiträgeZeigt meinen Blog an
  • RessourcenZeigt Ihnen eine Auswahl von Ressourcen
    • Franks aktueller IT-Werkzeugkasten
      • Diese Werkzeuge setze ich zur Zeit ein
    • Meine Präsentationen
      • Zeigt Ihnen meine Präsentationen
    • Weblinks
      • Meine Linksammlung
    • Buchtipps
      • Eine Liste von mir empfohlener Literatur
    • XML-Namespace
      • Zeigt meinem XML-Namespace
  • Franks aktueller IT-WerkzeugkastenDiese Werkzeuge setze ich zur Zeit ein
  • Meine PräsentationenZeigt Ihnen meine Präsentationen
  • WeblinksMeine Linksammlung
  • BuchtippsEine Liste von mir empfohlener Literatur
  • XML-NamespaceZeigt meinem XML-Namespace
  • Über mich …Die persönlichen Informationen über den Softwarearchitekt Frank Rahn
  • Click to open the search input field Click to open the search input field Suche
  • Menü Menü
Artikel, Beispiele und Vorträge

Wer ist der optimale Java Bean Mapper?

Das Klassendiagramm für den Java Bean Mapper Test am Beispiel "ByHand"

Ich hatte ein Problem. Ich hatte einen Webservice zu implementieren.

Dabei musste ich die interne Objekthierarchie einer Anwendung auf ca. 23 Servicemethoden mappen. Zusätzlich musste der Webservice aus einem komplexen Objektgeflecht bestückt werden.

Hätte ich dieses Mapping von Hand programmiert, wäre ich Wochen damit beschäftigt gewesen. Eine Lösung dieses Problems sind die Java Bean Mapper.

In diesem Beitrag zeige ich, welche Java Bean Mapper es gibt und welche Probleme damit gelöst bzw. aufgetreten sind.

Zusätzlich habe ich die Performanz der Java Bean Mappers miteinander verglichen.

Inhaltsverzeichnis [verstecken]

  • Die Aufgabe
    • Probleme über Probleme
  • Die Testimplementation
    • Die Objekthierarchie
    • Der JUnit Test
  • Die getesteten Java Bean Mapper mit Bewertung und Hinweise zur Implementierung
    • ByHand
    • Apache Commons BeanUtils
    • Spring Framework BeanUtils
    • Dozer
      • Update
    • Orika
      • Update
    • MapStruct
    • ModelMapper
    • JMapper Framework
      • Update
    • Selma
      • Update
    • reMap
      • Update
  • Das Fazit
  • Die Umfragen
  • Der Quellcode und Download
  • Die Maven Befehle
    • Durchführen der Messungen

Die Aufgabe

… ist ein typisches Problem aus der Praxis. Das Mappen von strukturierten Daten an Schnittstellen bzw. in Endpoints.

Dort werden die Daten der Schnittstelle auf die interne Objekthierarchie der Anwendung gemappt.

Dabei können bei einer umfangreichen Schnittstelle mit einem komplexen Sachverhalt recht aufwändige Objektgeflechte entstehen. Erschwerend kommt noch die Verschiedenartigkeit der aneinandergrenzenden Anwendungsschichten (Persistenz-, Domain-, Service-, REST- oder Web-API) hinzu.

Werden diese Objektgeflechte von Hand gemappt, sind Fehler vorprogrammiert. Daher wird immer die Frage nach einem automatischen Mapping gestellt.

Zur Lösung des Problems fiel meine Wahl auf den Klassiker – Dozer.

Leider stellte sich recht schnell heraus, dass die Performanz dieses Mappers nicht ausreichend für die Lösung des Problems war.

Probleme über Probleme

Bei der Suche nach alternativen Java Bean Mapper traten weitere Hindernisse auf.

  • Einige Mapper kamen mit den generierten JAXB-Klassen nicht zurecht, da die JAXB-Klassen nicht nach dem Java Bean Standard generiert werden. Die Collections haben keinen Setter Methoden und die Getter Methoden liefern immer eine Collection zurück.
public class XmlTable implements Serializable {
    protected List<XmlRow> rows;

    public List<XmlRow> getRows() {
        if (rows == null) {
            rows = new ArrayList<XmlRow>();
        }
        return this.rows;
    }

}
  • Auch die erweiterte Generierung der JAXB-Klassen mit dem XJC-Plugin jaxb2-basics half nicht weiter.
  • Dieses Plugin generiert für die Collections Setter Methoden. Aber bei einem nicht gesetzten Property wird die Setter Methode mit null aufgerufen. Daran stört sich aber die Methode addAll().
    public void setRows(List<XmlRow> value) {
        this.rows = null;
        List<XmlRow> draftl = this.getRows();
        draftl.addAll(value);
    }
  • Einige Mapper können nicht rekursiv durch die Objekthierarchie iterieren.
  • Somit wurden die in Collections enthaltenen Objekte nicht gemappt – sondern nur kopiert. Dadurch landeten nicht die erwarteten Klassen in den gemappten Objekten.
  • Ein Beispiel ist das Mappen einer DomainTable auf eine XmlTable. Beide Klassen haben ein Property rows. Im Falle der DomainTable ist das Property vom Typ List<DomainRow> rows; und der XmlTable vom Typ List<XmlRow> rows;. Nach dem Mappen von DomainTable auf die XmlTable befindet sich im Property Objekte vom Typ DomainRow.

Die Testimplementation

Wie hab ich den Test aufgebaut?

Der Test besteht aus zwei Testläufen, die die obengenannten Probleme berücksichtigt.

  1. Die Objekthierarchie wird vollständig mit Daten gefüllt.
    Leider können nicht alle Java Bean Mapper bei diesem Test eingeschossen werden. Die Mapper, die die obengenannten Probleme haben, wurden hier nicht berücksichtigt.
  2. Die Objekthierarchie wird teilweise mit Daten gefüllt.
    Bei diesem einfachen Test konnten alle Java Bean Mapper berücksichtigt werden. Allerdings ist die Aussagefähigkeit dieses Tests in der Praxis fraglich, da wesentliche Funktionen fehlen.

Die Links zum Quellcode finden Sie weiter unten.

Die Objekthierarchie

In diesem Beispiel werden zwei Objekthierarchien (JAXB– und JPA-Klassen) aufeinander gemappt. Es wird der Standard Jakarta EE 10 verwendet.

Die Eingangsdatenstruktur wurde aus der WSDL (https://xmlns.frank-rahn.de/ws/test/1.0) einmalig per JAXB generiert. Die generierten Klassen wurden danach im Source-Verzeichnis abgelegt.

Die Ausgangsdatenstruktur besteht aus JPA Entities.

In den folgenden UML-Diagrammen sind die Objekthierarchien der JAXB– und JPA-Klassen dargestellt.

Die JavaBeans der JAXB-Klassen für Testzwecken
Die JavaBeans der JAXB-Klassen für Testzwecken
Die JavaBeans der JPA-Klassen für Testzwecken
Die JavaBeans der JPA-Klassen für Testzwecken

Der JUnit Test

In der Klasse AbstractPerformanceTest wird in der Methode runTestWithMapper() für jeden Java Bean Mapper das Mapping durchgeführt. Für jeden Durchlauf werden die Daten erfasst. Vor jeder Messreihe werden alle Mapper 10-mal aufgerufen, um den Test bzw. die Implementationen einzuschwingen. Der eigentliche Test läuft dann 10 Minuten.

Es wird die durchschnittliche Dauer in Abhängigkeit von der Anzahl der Durchläufe ermittelt.

Zusätzlich werden folgende Kenndaten über die Dauer ermittelt.

  • Minimaler Wert
  • Maximaler Wert
  • Letzter gemessener Wert
  • Arithmetischer Mittelwert
  • Standardabweichung

Die Ergebnisse werden in einem Excel-Sheet dargestellt. Die Dauer wird in Millisekunden angegeben.

Im folgenden Klassendiagramm ist die Objekthierarchie des JUnit-Tests dargestellt.

Das Klassendiagramm für den Java Bean Mapper Test am Beispiel "ByHand"

Das Klassendiagramm für den Java Bean Mapper Test am Beispiel 'ByHand' (© Frank Rahn)

Die getesteten Java Bean Mapper mit Bewertung und Hinweise zur Implementierung

Bei der Implementierung habe ich darauf geachtet, dass keine Technik zum Einsatz kommt, die eine direkte Änderung des Quellcodes der JAXB- bzw. JPA-Klassen erzwungen hätte. Z. B. durch den Einsatz einer speziellen Annotation eines Mapper Frameworks.

Die folgenden Java Bean Mapper wurden von mir untersucht.

ByHand

Der Java Bean Mapper ByHand ist kein automatisch generierter Mapper.

Dieser Java Bean Mapper ist eine Implementierung von Hand (hand coded). Hierbei wird jedes einzelne Property von einem Java Bean in ein anderes Java Bean, ggf. mit Typkonvertierung, übertragen.

Das Erstellen dieses Mappers ist sehr zeitintensiv und fehleranfällig. Eigentlich eine Aufgabe für einen dressierten Affen. Allerdings können alle fachlichen Aspekte individuell berücksichtigt werden.

Diese Art von Mappern liefert die beste Performanz.

/**
 * Der Mapper per "ByHand".
 *
 * @author Frank W. Rahn
 */
@Component("ByHand")
@Order(0)
public class ByHandTestBeansMapperBean extends AbstractTestBeansMapperBean {

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return map(createXmlTable(), source);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return map(new DomainTable(), source);
  }

  private DomainRow map(DomainRow target, XmlRow source) {
    // Mapping String
    target.setColumn00(source.getColumn00());
    target.setColumn01(source.getColumn01());
    target.setColumn02(source.getColumn02());
    target.setColumn03(source.getColumn03());
    target.setColumn04(source.getColumn04());
    target.setColumn05(source.getColumn05());
    target.setColumn06(source.getColumn06());
    target.setColumn07(source.getColumn07());
    target.setColumn08(source.getColumn08());
    target.setColumn09(source.getColumn09());

    // Mapping int
    target.setColumn10(source.getColumn10());
    target.setColumn11(source.getColumn11());
    target.setColumn12(source.getColumn12());
    target.setColumn13(source.getColumn13());
    target.setColumn14(source.getColumn14());
    target.setColumn15(source.getColumn15());
    target.setColumn16(source.getColumn16());
    target.setColumn17(source.getColumn17());
    target.setColumn18(source.getColumn18());
    target.setColumn19(source.getColumn19());

    // Mapping boolean
    target.setColumn20(source.isColumn20());
    target.setColumn21(source.isColumn21());
    target.setColumn22(source.getColumn22());
    target.setColumn23(source.isColumn23());
    target.setColumn24(source.isColumn24());
    target.setColumn25(source.isColumn25());
    target.setColumn26(source.isColumn26());
    target.setColumn27(source.isColumn27());
    target.setColumn28(source.isColumn28());
    target.setColumn29(source.isColumn29());

    // Mapping long
    target.setColumn30(source.getColumn30());
    target.setColumn31(source.getColumn31());
    target.setColumn32(source.getColumn32());
    target.setColumn33(source.getColumn33());
    target.setColumn34(source.getColumn34());
    target.setColumn35(source.getColumn35());
    target.setColumn36(source.getColumn36());
    target.setColumn37(source.getColumn37());
    target.setColumn38(source.getColumn38());
    target.setColumn39(source.getColumn39());

    // Mapping BigDecimal
    target.setColumn40(source.getColumn40());
    target.setColumn41(source.getColumn41());
    target.setColumn42(source.getColumn42());
    target.setColumn43(source.getColumn43());
    target.setColumn44(source.getColumn44());
    target.setColumn45(source.getColumn45());
    target.setColumn46(source.getColumn46());
    target.setColumn47(source.getColumn47());
    target.setColumn48(source.getColumn48());
    target.setColumn49(source.getColumn49());

    // Mapping Calendar
    target.setColumn50(source.getColumn50());
    target.setColumn51(source.getColumn51());
    target.setColumn52(source.getColumn52());
    target.setColumn53(source.getColumn53());
    target.setColumn54(source.getColumn54());
    target.setColumn55(source.getColumn55());
    target.setColumn56(source.getColumn56());
    target.setColumn57(source.getColumn57());
    target.setColumn58(source.getColumn58());
    target.setColumn59(source.getColumn59());

    // Mapping String
    target.setColumn60(source.getColumn60());
    target.setColumn61(source.getColumn61());
    target.setColumn62(source.getColumn62());
    target.setColumn63(source.getColumn63());
    target.setColumn64(source.getColumn64());
    target.setColumn65(source.getColumn65());
    target.setColumn66(source.getColumn66());
    target.setColumn67(source.getColumn67());
    target.setColumn68(source.getColumn68());
    target.setColumn69(source.getColumn69());

    // Mapping int
    target.setColumn70(source.getColumn70());
    target.setColumn71(source.getColumn71());
    target.setColumn72(source.getColumn72());
    target.setColumn73(source.getColumn73());
    target.setColumn74(source.getColumn74());
    target.setColumn75(source.getColumn75());
    target.setColumn76(source.getColumn76());
    target.setColumn77(source.getColumn77());
    target.setColumn78(source.getColumn78());
    target.setColumn79(source.getColumn79());

    // Mapping String[]
    if (source.getColumns() != null) {
      target.setColumns(new ArrayList<>(source.getColumns()));
    }

    return target;
  }

  private DomainTable map(DomainTable target, XmlTable source) {
    target.setName(source.getName());

    if (source.getDate() != null) {
      target.setDate(source.getDate().getTime());
    }

    if (source.getRows().isEmpty()) {
      target.setRows(new ArrayList<DomainRow>());
    } else {
      List<DomainRow> rows = new ArrayList<>();
      for (XmlRow xmlRow : source.getRows()) {
        rows.add(map(new DomainRow(), xmlRow));
      }
      target.setRows(rows);
    }

    return target;
  }

  private XmlRow map(XmlRow target, DomainRow source) {
    // Mapping String
    target.setColumn00(source.getColumn00());
    target.setColumn01(source.getColumn01());
    target.setColumn02(source.getColumn02());
    target.setColumn03(source.getColumn03());
    target.setColumn04(source.getColumn04());
    target.setColumn05(source.getColumn05());
    target.setColumn06(source.getColumn06());
    target.setColumn07(source.getColumn07());
    target.setColumn08(source.getColumn08());
    target.setColumn09(source.getColumn09());

    // Mapping int
    target.setColumn10(source.getColumn10());
    target.setColumn11(source.getColumn11());
    target.setColumn12(source.getColumn12());
    target.setColumn13(source.getColumn13());
    target.setColumn14(source.getColumn14());
    target.setColumn15(source.getColumn15());
    target.setColumn16(source.getColumn16());
    target.setColumn17(source.getColumn17());
    target.setColumn18(source.getColumn18());
    target.setColumn19(source.getColumn19());

    // Mapping boolean
    target.setColumn20(source.isColumn20());
    target.setColumn21(source.isColumn21());
    target.setColumn22(source.getColumn22());
    target.setColumn23(source.isColumn23());
    target.setColumn24(source.isColumn24());
    target.setColumn25(source.isColumn25());
    target.setColumn26(source.isColumn26());
    target.setColumn27(source.isColumn27());
    target.setColumn28(source.isColumn28());
    target.setColumn29(source.isColumn29());

    // Mapping long
    target.setColumn30(source.getColumn30());
    target.setColumn31(source.getColumn31());
    target.setColumn32(source.getColumn32());
    target.setColumn33(source.getColumn33());
    target.setColumn34(source.getColumn34());
    target.setColumn35(source.getColumn35());
    target.setColumn36(source.getColumn36());
    target.setColumn37(source.getColumn37());
    target.setColumn38(source.getColumn38());
    target.setColumn39(source.getColumn39());

    // Mapping BigDecimal
    target.setColumn40(source.getColumn40());
    target.setColumn41(source.getColumn41());
    target.setColumn42(source.getColumn42());
    target.setColumn43(source.getColumn43());
    target.setColumn44(source.getColumn44());
    target.setColumn45(source.getColumn45());
    target.setColumn46(source.getColumn46());
    target.setColumn47(source.getColumn47());
    target.setColumn48(source.getColumn48());
    target.setColumn49(source.getColumn49());

    // Mapping Calendar
    target.setColumn50(source.getColumn50());
    target.setColumn51(source.getColumn51());
    target.setColumn52(source.getColumn52());
    target.setColumn53(source.getColumn53());
    target.setColumn54(source.getColumn54());
    target.setColumn55(source.getColumn55());
    target.setColumn56(source.getColumn56());
    target.setColumn57(source.getColumn57());
    target.setColumn58(source.getColumn58());
    target.setColumn59(source.getColumn59());

    // Mapping String
    target.setColumn60(source.getColumn60());
    target.setColumn61(source.getColumn61());
    target.setColumn62(source.getColumn62());
    target.setColumn63(source.getColumn63());
    target.setColumn64(source.getColumn64());
    target.setColumn65(source.getColumn65());
    target.setColumn66(source.getColumn66());
    target.setColumn67(source.getColumn67());
    target.setColumn68(source.getColumn68());
    target.setColumn69(source.getColumn69());

    // Mapping int
    target.setColumn70(source.getColumn70());
    target.setColumn71(source.getColumn71());
    target.setColumn72(source.getColumn72());
    target.setColumn73(source.getColumn73());
    target.setColumn74(source.getColumn74());
    target.setColumn75(source.getColumn75());
    target.setColumn76(source.getColumn76());
    target.setColumn77(source.getColumn77());
    target.setColumn78(source.getColumn78());
    target.setColumn79(source.getColumn79());

    // Mapping String[]
    if (source.getColumns() == null) {
      target.setColumns(null);
    } else {
      target.setColumns(new ArrayList<>(source.getColumns()));
    }

    return target;
  }

  private XmlTable map(XmlTable target, DomainTable source) {
    target.setName(source.getName());

    if (source.getDate() != null) {
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(source.getDate());
      target.setDate(calendar);
    }

    if (source.getRows() != null) {
      for (DomainRow domainRow : source.getRows()) {
        target.getRows().add(map(createXmlRow(), domainRow));
      }
    }

    return target;
  }

}

Apache Commons BeanUtils

Dieser Java Bean Mapper ist Teil der Bibliothek Apache Commons BeanUtils der Apache Software Foundation. Dieses Projekt stellt nützliche Tools rund um den Standard JavaBeans Component API java.beans.Introspector zu Verfügung und verwendet zum Mappen Reflection (reflection-based).

Der Mapper besteht aus der Klasse org.apache.commons.beanutils.BeanUtils. Dieser Mapper kann das zumappende Objekt nicht rekursive bearbeiten und ist auf die Setter Methode angewiesen – ohne diese kann er die Werte nicht mappen.

Daher kann er nur für einfache und nicht tiefgreifende Mappings verwendet werden.

In diesen Fällen allerdings liefert er eine gute Performanz und ist sehr einfach eingesetzt.

/**
 * Der Mapper für {@link BeanUtils}.
 *
 * @author Frank W. Rahn
 */
@Component("Commons-BeanUtils")
@Order(1)
public class CommonsBeanUtilsTestBeansMapperBean extends AbstractTestBeansMapperBean {

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    XmlTable target = createXmlTable();
    BeanUtils.copyProperties(target, source);
    return target;
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    DomainTable target = new DomainTable();
    BeanUtils.copyProperties(target, source);
    return target;
  }

}

Spring Framework BeanUtils

Dieser Java Bean Mapper ist Teil vom Spring Framework und wird intern vom Spring Framework selber verwendet.

Der Mapper besteht aus der Klasse org.springframework.beans.BeanUtils. Diese Klasse nutzt den Standard JavaBeans Component API java.beans.Introspector und verwendet Reflection (reflection-based).

Dieser Mapper arbeitet ähnlich wie die Apache Common BeanUtils, hat die gleichen Probleme und liefert die gleiche Performanz.

Update (01.01.2020): Seit der Spring Framework Version 5.3 hat sich das Vorgehen beim Mappen von Collection geändert. Die generischen Typinformationen werden jetzt berücksichtigt. Dadurch werden Collection nur noch gemappt, wenn der generische Typ passt. Vorher war die Klasse der Collection entscheidend.

/**
 * Der Mapper für {@link BeanUtils}.
 *
 * @author Frank W. Rahn
 */
@Component("Spring-BeanUtils")
@Order(2)
public class SpringBeanUtilsTestBeansMapperBean extends AbstractTestBeansMapperBean {

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    XmlTable target = createXmlTable();
    BeanUtils.copyProperties(source, target);
    return target;
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    DomainTable target = new DomainTable();
    BeanUtils.copyProperties(source, target);
    return target;
  }

}

Dozer

Der Java Bean Mapper Dozer ist ein komplettes Mapping Framework.

Dozer verwendet den Standard JavaBeans Component API java.beans.Introspector und Reflection (reflection-based) zum Erzeugen der Mapper und kann die Objekte rekursiv durcharbeiten.

Dozer kann über eine XML-Datei umfangreich konfiguriert werden. Die Möglichkeiten der Konfiguration dieses Mappers lassen keine Wünsche offen.

Wie beim Mapper ByHand können alle individuellen fachlichen Aspekte berücksichtigt werden. Die Konfiguration geht schnell vonstatten.

Leider liefert dieser Mapper aber auch die schlechteste Performanz.

/**
 * Der Mapper für {@link Mapper}.
 *
 * @author Frank W. Rahn
 */
@Component("Dozer")
@Order(3)
public class DozerTestBeansMapperBean extends AbstractTestBeansMapperBean {

  private Mapper dozer;

  /**
   * Initialisiere diese Spring-Bean.
   */
  @PostConstruct
  public void initialize() {
    dozer = DozerBeanMapperBuilder.create()
        // Bekannt geben, dass die Xml*-Klassen JAXB Objekte sind
        .withMappingBuilder(new BeanMappingBuilder() {
          @Override
          protected void configure() {
            mapping(new TypeDefinition(DomainTable.class),
                new TypeDefinition(XmlTable.class).beanFactory(JAXBBeanFactory.class));
          }
        })
        .withMappingBuilder(new BeanMappingBuilder() {
          @Override
          protected void configure() {
            mapping(new TypeDefinition(DomainRow.class),
                new TypeDefinition(XmlRow.class).beanFactory(JAXBBeanFactory.class));
          }
        })
        .build();
  }

  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return dozer.map(source, XmlTable.class);
  }

  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return dozer.map(source, DomainTable.class);
  }
}

Update (Fehlende Versionen 6.0.0 bis 6.5.0): Hier ist mir leider ein Fehler unterlaufen. Wenn ich in diesen Beitrag aktualisieren, schaue ich immer in den zentralen Maven-Repositories nach, ob dort neue Versionen veröffentlicht wurden. Dabei verwende ich die Maven-Suche mit dem Artefaktnamen. In diesem Punkt habe ich leider die Änderung im Artefaktnamen (net.sf.dozer:dozer → com.github.dozermapper:dozer-core) übersehen und so hat sich nie die Versionsnummer geändert.

Update (07.04.2021): Dieser Mapper wird nicht mehr weiterentwickelt.

The project is currently not active and will more than likely be deprecated in the future.

https://github.com/DozerMapper/dozer/blob/master/README.md#project-activity

Update (05.03.2024): Es ist eine neue Version 7.0.0 aufgetaucht, ob wohl der Mapper nicht mehr weiter entwickelt wird. Eine Aktivierung des Projektes ist aber nicht geschehen.

Orika

Der Java Bean Mapper Orika ist ähnlich wie Dozer ein Mapping Framework.

Im Grunde stellt Orika einen Replacment von Dozer mit gleichem Funktionsumfang dar.

Allerdings verwendet Orika die Bytecode Generierung von Javassist zum Erzeugen der Mapper. Dadurch hat Orika, bei gleichem Funktionsumfang, eine deutlich bessere Performanz als Dozer. Allerdings können die generierten Mapper nicht debuggt werden.

/**
 * Der Mapper für {@link MapperFacade}.
 *
 * @author Frank W. Rahn
 */
@Component("Orika")
@Order(4)
public class OrikaTestBeansMapperBean extends AbstractTestBeansMapperBean {

  private MapperFacade orika;

  /**
   * Initialisiere diese Spring-Bean.
   */
  @PostConstruct
  public void initialize() {
    MapperFactory factory = new DefaultMapperFactory.Builder().build();
    orika = factory.getMapperFacade();
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return orika.map(source, XmlTable.class);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return orika.map(source, DomainTable.class);
  }

}

Update (22.09.2023): Wie in den Kommentaren beschrieben, ist dieser Mapper nicht unter Java 17 lauffähig. Daher werde ich diesen Mapper nicht mehr berücksichtigen.

Fehler:
java.lang.reflect.InaccessibleObjectException: Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not "opens java.lang" to unnamed module

Befehlszeile mit JVM-Optionen:
$ java --add-opens=java.base/java.lang=ALL-UNNAMED -jar app.jar

Update (02.01.2026): Ich habe das Maven-Plugin maven-surefire-plugin, um die oben genannten JVM-Optionen erweitert. Damit konnte der Mapper unter Java 21 wieder berücksichtigt werden.

MapStruct

Der Java Bean Mapper MapStruct ist auch ein Mapping Framework.

Allerdings geht dieser Mapper einen kompletten neuen Weg.

Er verwendet einen Annotation Processor (APT) zum Erzeugen von Mappern für die einzelnen Java Beans. Diese generierten Mapper sind richtige Java-Klassen – können also im Fehlerfall auch debuggt werden.

Als Ausgangsbasis dient dem Prozessor ein Interface oder eine abstrakte Basisklasse.

Falls Sie sich für eine abstrakte Basisklasse entscheiden, kann diese Klasse eine individuelle Implementierungen liefern. Damit erreicht dieses Mapping den vollständigen Funktionsumfang wie der Mapper ByHand. Allerdings auch zu einem höheren Implementierungsaufwand im Gegensatz zu Dozer oder Orika.

Diese Interfaces müssen geschrieben werden. Bei einer umfangreichen Objekthierarchie benötigt das Schreiben der Interfaces seine Zeit.

Die dadurch gewonnene Performanz hebt diesen Nachteil allerdings vollständig auf. Dieser Mapper wurde nur geringfügig (im Bereich von Millisekunden) durch den Mapper ByHand geschlagen. Der wesentlich mühseliger zu programmieren ist.

/**
 * Der Mapper für MapStruct.
 *
 * @author Frank W. Rahn
 */
@Component("MapStruct")
@Order(5)
public class MapStructTestBeansMapperBean extends AbstractTestBeansMapperBean {

  @Autowired
  private TestBeansMapper testBeansMapper;

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return testBeansMapper.domainTableToXmlTable(source);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return testBeansMapper.xmlTableToDomainTable(source);
  }

}

ModelMapper

Die Berücksichtigung des Java Bean Mapper ModelMapper wurde in den Kommentaren gewünscht.

Dieser Mapper ähnelt in der Funktionsweise den schon vorher beschriebenen Mappern Orika und Dozer. Dieser Mapper verwendet die Bytecode Generierung von cglib. Das Debuggen der erzeugten Mapper gestaltet sich dadurch schwierig.

Dieser Mapper bietet eine API für spezifische Anwendungsfälle an.

/**
 * Der Mapper für {@link ModelMapper}.
 *
 * @author Frank W. Rahn
 */
@Component("ModelMapper")
@Order(6)
public class ModelMapperTestBeansMapperBean extends AbstractTestBeansMapperBean {

  private ModelMapper modelMapper;

  /**
   * Initialisiere diese Spring-Bean.
   */
  @PostConstruct
  public void initialize() {
    modelMapper = new ModelMapper();
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return modelMapper.map(source, XmlTable.class);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return modelMapper.map(source, DomainTable.class);
  }

}

JMapper Framework

Die Berücksichtigung des Java Bean Mapper JMapper Framework wurde in den Kommentaren gewünscht.

Dieser Mapper ähnelt einwenig dem Mapper MapStruct. Auch bei diesem Mapper muss zwingend eine Konfiguration erstellt werden. Beim JMapper kann zwischen drei Konfigurationsvarianten gewählt werden.

  • Der Verwendung von Annotationen an den Klassen
  • Eine Konfiguration basierend auf einer XML Datei
  • Der JMapper API, welche eine programmatische Konfiguration ermöglicht

Ich habe mich in diesem Beispiel für die Variante JMapper API entschieden.

Der JMapper verwendet die Bytecode Generierung von Javassist zum Erzeugen der Mapper. Das Debuggen der erzeugten Mapper gestaltet sich dadurch schwierig.

Die Performanz dieses Mappers ist beeindruckend. Er kann locker mit dem Mapper ByHand mithalten und ist einfacher umzusetzen als der Mapper MapStruct.

Weitere Features dieses Mappers sind …

  • Relationales Mapping von mehreren Klassen auf eine Klasse (Many to One) und umgekehrt (One to Many)
  • Vererbung von Konfigurationen
/**
 * Der Mapper für {@link JMapper}.
 *
 * @author Frank W. Rahn
 */
@Component("JMapper")
@Order(7)
public class JMapperTestBeansMapperBean extends AbstractTestBeansMapperBean {

  private JMapper<XmlTable, DomainTable> domainToXmlMapper;

  private JMapper<DomainTable, XmlTable> xmlToDomainMapper;

  /**
   * Initialisiere diese Spring-Bean.
   */
  @PostConstruct
  public void initialize() {
    JMapperAPI jMapperAPI = new JMapperAPI()
      .add(mappedClass(XmlTable.class).add(global())
        .add(conversion("dateToCalendar").from("date").to("date")
          .body("java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(${source}); return c;")))
      .add(mappedClass(XmlRow.class).add(global()))
      .add(mappedClass(DomainTable.class).add(global().excludedAttributes("id"))
        .add(conversion("calendarToDate").from("date").to("date").body("return ${source}.getTime();"))
        .add(attribute("rows").value("rows").targetClasses(DomainRow.class)))
      .add(mappedClass(DomainRow.class).add(global().excludedAttributes("id")));

    domainToXmlMapper = new JMapper<>(XmlTable.class, DomainTable.class, jMapperAPI);
    xmlToDomainMapper = new JMapper<>(DomainTable.class, XmlTable.class, jMapperAPI);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return domainToXmlMapper.getDestination(source);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return xmlToDomainMapper.getDestination(source);
  }

}

Update (01.01.2021): Dieser Mapper wird nicht mehr weiterentwickelt. Der Entwickler schrieb im GitHub Issue 88 dazu:

… I’ve lost interest in JMapper …

https://github.com/jmapper-framework/jmapper-core/issues/88

Update (10.12.2022): Wie in den Kommentaren beschrieben, ist dieser Mapper nicht unter Java 17 lauffähig. Daher werde ich diesen Mapper nicht mehr berücksichtigen.

Fehler (XStream):
java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module

java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module

java.lang.reflect.InaccessibleObjectException: Unable to make field protected java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.h accessible: module java.base does not "opens java.lang.reflect" to unnamed module

java.lang.reflect.InaccessibleObjectException: Unable to make protected java.lang.String java.text.AttributedCharacterIterator$Attribute.getName() accessible: module java.base does not "opens java.text" to unnamed module

java.lang.reflect.InaccessibleObjectException: Unable to make field private static final java.util.Map java.awt.font.TextAttribute.instanceMap accessible: module java.desktop does not "opens java.awt.font" to unnamed module

Befehlszeile mit JVM-Optionen:
$ java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED -jar app.jar

Update (02.01.2026): Ich habe das Maven-Plugin maven-surefire-plugin, um die oben genannten JVM-Optionen erweitert. Damit konnte der Mapper unter Java 21 wieder berücksichtigt werden.

Selma

Die Berücksichtigung des Java Bean Mapper Selma wurde in den Kommentaren gewünscht.

Dieser Mapper verwendet einen Annotation Processor (APT) zum Erzeugen der Mapper und ähnelt damit dem schon vorher beschriebenen Mapper MapStruct.

Im Gegensatz zu MapStruct ist der Aufwand für die Implementierung etwas geringer, da nicht für jedes Mapping eine neue Methode definiert werden muss.

/**
 * Der Mapper für {@link Selma}.
 *
 * @author Frank W. Rahn
 */
@Component("Selma")
@Order(8)
public class SelmaTestBeansMapperBean extends AbstractTestBeansMapperBean {

  @Autowired
  private TestBeansMapper mapper;

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return mapper.asXmlTable(source);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return mapper.asDomainTable(source);
  }

}

Update (03.01.2021): Seit dem Umstieg auf das OpenJDK v11 (64 Bit, AdoptOpenJDK Hotspot) werden in Eclipse v4.16.0 zwei Fehler angezeigt – trotzdem wird der Mapper generiert. Maven liefert dazu keine Meldungen. Diese Meldungen können ignoriert werden. Dazu gibt es auch eine Meldung in GitHub Issue 204: Migration Java 8 -> Java 11: mapper: java.lang.NullPointerException.

Error while searching builder for field name on InOutType{in=de.rahn.performance.testbeans.DomainTable, out=https.xmlns_frank_rahn_de.types.testtypes._1.XmlTable, outPutAsParam=false} mapper: java.lang.NullPointerException
Error while searching builder for field name on InOutType{in=https.xmlns_frank_rahn_de.types.testtypes._1.XmlTable, out=de.rahn.performance.testbeans.DomainTable, outPutAsParam=false} mapper: java.lang.NullPointerException

Update (04.01.2022): Mittlerweile bin ich von AdoptOpenJDK wieder auf das Standard OpenJDK zurückgewechselt, da dieses sich unter Ubuntu besser ins System (Stichwort: Zertifikate, …) integriert. Wenn ich die Tests in Eclipse ausführe, tritt leider ein Fehler auf. Die Unterobjekte werden nicht mehr gemappt. Ich hab dazu das Erstellen der Messungen verändert. Ab der Version v1.5.3 werden die Excel-Sheets per Maven auf der Kommandozeile erzeugt (Siehe Durchführung der Messungen). Da gibt es den Fehler, wie in Eclipse, nicht.

reMap

Die Berücksichtigung des Java Bean Mapper reMap wurde in den Kommentaren gewünscht.

reMap verwendet die Bytecode Generierung von cglib zur Erzeugung von Mappern. Das Debuggen der erzeugten Mapper gestaltet sich dadurch schwierig.

Der Schwerpunkt von reMap liegt in der Robustheit und einem minimalen Verwaltungsaufwand für Tests.

Durch das Hauptaugenmerk auf Robustheit müssen mehr Angaben zum Mapping gemacht werden, als bei anderen Mappern nötig ist. Aber es ist gewollt, dass hier wenige Automatik greift und einiges dem Compiler überlassen wird.

/**
 * Der Mapper für {@link Mapper}.
 *
 * @author Tom Hombergs
 */
@Component("reMap")
@Order(9)
public class ReMapTestBeansMapperBean implements TestBeansMapperBean {

  protected Mapper<DomainTable, XmlTable> domainToXmlTableMapper;

  protected Mapper<XmlTable, DomainTable> xmlToDomainTableMapper;

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#getMapperName()
   */
  @Override
  public String getMapperName() {
    return "reMap";
  }

  /**
   * Initialisiere diese Spring-Bean.
   */
  @PostConstruct
  public ReMapTestBeansMapperBean initialize() {
    Mapper<DomainRow, XmlRow> domainToXmlRowMapper = Mapping.from(DomainRow.class).to(XmlRow.class).mapper();
    Mapper<XmlRow, DomainRow> xmlToDomainRowMapper = Mapping.from(XmlRow.class).to(DomainRow.class).mapper();

    // @formatter:off
    domainToXmlTableMapper = Mapping
      .from(DomainTable.class)
      .to(XmlTable.class)
      .replace(DomainTable::getDate, XmlTable::getDate)
        .with(dateToCalendar())
      .useMapper(domainToXmlRowMapper)
      .mapper();

    xmlToDomainTableMapper = Mapping
      .from(XmlTable.class)
      .to(DomainTable.class)
      .replace(XmlTable::getDate, DomainTable::getDate)
        .with(calendarToDate())
      .useMapper(xmlToDomainRowMapper).mapper();
    // @formatter:on

    return this;
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(DomainTable)
   */
  @Override
  public XmlTable map(DomainTable source) throws Exception {
    return domainToXmlTableMapper.map(source);
  }

  /**
   * {@inheritDoc}
   *
   * @see TestBeansMapperBean#map(XmlTable)
   */
  @Override
  public DomainTable map(XmlTable source) throws Exception {
    return xmlToDomainTableMapper.map(source);
  }

  /**
   * @return ein Transformer von {@link Date} nach {@link Calendar}
   */
  protected Function<Date, Calendar> dateToCalendar() {
    return source -> {
      if (source == null) {
        return null;
      }

      Calendar c = Calendar.getInstance();
      c.setTime(source);
      return c;
    };
  }

  /**
   * @return ein Transformer von {@link Calendar} nach {@link Date}
   */
  protected Function<Calendar, Date> calendarToDate() {
    return source -> {
      if (source == null) {
        return null;
      }

      return source.getTime();
    };
  }

}

Im folgenden Quellcode die Beispiele für die Tests des Mappers.

/**
 * Test des Mappers für reMap.
 *
 * @author Tom Hombergs
 */
public class ReMapTestBeansMapperBeanTest extends AbstractTestBeansMapperBeanTest {

  /**
   * @throws java.lang.Exception
   */
  @Before
  public void setUp() throws Exception {
    mapperBean = new ReMapTestBeansMapperBean().initialize();
  }

  /**
   * Teste den Mapper.
   */
  @Test
  public void testDomainToXmlTableMapper() throws Exception {
    ReMapTestBeansMapperBean reMapTestBeansMapperBean = (ReMapTestBeansMapperBean) mapperBean;

    // @formatter:off
    AssertMapping.of(reMapTestBeansMapperBean.domainToXmlTableMapper)
      .expectReplace(DomainTable::getDate, XmlTable::getDate)
        .andTest(reMapTestBeansMapperBean.dateToCalendar())
      .ensure();
    // @formatter:on
  }

  /**
   * Teste den Mapper.
   */
  @Test
  public void testXmlToDomainTableMapper() throws Exception {
    ReMapTestBeansMapperBean reMapTestBeansMapperBean = (ReMapTestBeansMapperBean) mapperBean;

    // @formatter:off
    AssertMapping.of(reMapTestBeansMapperBean.xmlToDomainTableMapper)
      .expectReplace(XmlTable::getDate, DomainTable::getDate)
        .andTest(reMapTestBeansMapperBean.calendarToDate())
      .ensure();
    // @formatter:on
  }

}

Update (21.07.2025): Wie in den Kommentaren beschrieben, ist dieser Mapper nicht unter Java 21 lauffähig. Daher werde ich diesen Mapper nicht mehr berücksichtigen.

Fehler:
java.lang.UnsupportedOperationException: Cannot define class using reflection: Unable to make protected java.lang.Package java.lang.ClassLoader.getPackage(java.lang.String) accessible: module java.base does not "opens java.lang" to unnamed module

Befehlszeile mit JVM-Optionen:
$ java --add-opens=java.base/java.lang=ALL-UNNAMED -jar app.jar

Update (02.01.2026): Ich habe das Maven-Plugin maven-surefire-plugin, um die oben genannten JVM-Optionen erweitert. Damit konnte der Mapper unter Java 21 wieder berücksichtigt werden.

Das Fazit

In der folgenden Tabelle sind die Durchschnittswerte für ein Mapping mit vollständig gefüllter Objekthierarchie in Millisekunden angegeben. Die Veränderungen zur vorherigen Messung sind Fett markiert.

Die nicht mehr weiterentwickelten Mapper werden so lange weiter getestet, wie sie funktionieren.

Der Link „Anmerkungen“ zeigt auf zusätzlichen Informationen, wie z. B. Inaktivität oder wichtige Änderungen.

Aktualisierung der Messung: neue Versionen von Mapper vom 16.02.2026 (v1.7.2, jdk21-03)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01430,119
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00710,084
MapStruct
v1.6.3 vom 09.11.2024
0,01790,133
Orika
v1.5.4 vom 20.02.2019
Anmerkungen
0,41660,494
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,40780,492
reMap
v4.4.2 vom 30.07.2025
Anmerkungen
2,62130,541
Dozer
v7.0.0 vom 05.03.2024
Anmerkungen
5,29290,516
ModelMapper
v3.2.6 vom 11.11.2025
6,52550,614

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 21 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.4 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Alle Mapper wieder berücksichtigt vom 02.01.2026 (v1.7.1, jdk21-02)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01100,104
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00700,083
MapStruct
v1.6.3 vom 09.11.2024
0,01750,131
Orika
v1.5.4 vom 20.02.2019
Anmerkungen
0,38920,488
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39320,489
reMap
v4.4.0 vom 05.02.2025
Anmerkungen
2,65240,533
Dozer
v7.0.0 vom 05.03.2024
Anmerkungen
6,14000,553
ModelMapper
v3.2.4 vom 20.06.2025
6,58860,618

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 21 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Neu: Java 21 vom 21.07.2025 (v1.7.0, jdk21-01)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01100,104
MapStruct
v1.6.3 vom 09.11.2024
0,01460,120
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,383270,487
Dozer
v7.0.0 vom 05.03.2024
Anmerkungen
5,13930,493
ModelMapper
v3.2.4 vom 20.06.2025
6,20490,501

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Anmerkungen
Diese Version ist im Moment unter Java 17 nicht lauffähig
reMap
v4.4.0 vom 05.02.2025
Anmerkungen
Diese Version ist im Moment unter Java 21 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 21 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mapper vom 01.07.2025 (v1.6.2, jdk17-07)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01260,111
MapStruct
v1.6.3 vom 09.11.2024
0,01710,130
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39120,488
reMap
v4.4.0 vom 05.02.2025
3,60380,544
Dozer
v7.0.0 vom 05.03.2024
Anmerkungen
5,31380,529
ModelMapper
v3.2.4 vom 20.06.2025
6,37570,563

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mapper vom 17.05.2025 (v1.6.1, jdk17-06)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01470,120
MapStruct
v1.6.3 vom 09.11.2024
0,01650,127
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,38830,488
reMap
v4.4.0 vom 05.02.2025
3,46090,518
Dozer
v7.0.0 vom 05.03.2024
Anmerkungen
5,45820,525
ModelMapper
v3.2.3 vom 02.05.2025
6,29130,477

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.2 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Neue: Betriebssystem, Maven-Plugins vom 11.05.2025 (v1.6.0, jdk17-05)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01240,111
MapStruct
v1.5.5.Final vom 23.04.2023
0,01550,124
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,38800,487
reMap
v4.3.2 vom 28.04.2023
3,52870,529
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,52110,544
ModelMapper
v3.2.0 vom 16.10.2023
6,50920,540

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 24.04.2 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mapper vom 03.03.2024 (v1.5.10, jdk17-04)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01170,110
MapStruct
v1.5.5.Final vom 23.04.2023
0,01420,118
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,38820,488
reMap
v4.3.2 vom 28.04.2023
3,50180,538
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,26800,463
ModelMapper
v3.2.0 vom 16.10.2023
6,22340,486

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.6 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Entfernen der Generierung der JAXB-Klassen vom 25.02.2024 (v1.5.9, jdk17-03)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01210,110
MapStruct
v1.5.5.Final vom 23.04.2023
0,01410,118
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39790,491
reMap
v4.3.2 vom 28.04.2023
3,47900,531
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,24290,462
ModelMapper
v3.1.1 vom 08.12.2022
5,93640,391

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.6 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen der Maven-Plugins vom 18.02.2024 (v1.5.8, jdk17-02)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01120,105
MapStruct
v1.5.5.Final vom 23.04.2023
0,01360,116
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,38690,488
reMap
v4.3.2 vom 28.04.2023
3,51390,545
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,35910,534
ModelMapper
v3.1.1 vom 08.12.2022
6,03710,300

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.6 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mapper und Java 17 vom 22.09.2023 (v1.5.7, jdk17-01)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01240,112
MapStruct
v1.5.5.Final vom 23.04.2023
0,01530,123
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,37660,485
reMap
v4.3.2 vom 28.04.2023
3,44480,525
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,14950,402
ModelMapper
v3.1.1 vom 08.12.2022
5,96290,396

Nicht mehr getestete Mapper
Orika
v1.5.4 vom 20.02.2019
Diese Version ist im Moment unter Java 17 nicht lauffähig
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
Dieser Mapper wird nicht mehr weiterentwickelt (EOL) und ist unter Java 17 nicht mehr lauffähig

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 17 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.6 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mapper vom 03.10.2022 (v1.5.6, jdk11-05)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01260,122
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00660,081
MapStruct
v1.5.2.Final vom 18.06.2022
0,01560,128
Orika
v1.5.4 vom 20.02.2019
0,24910,438
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,38220,495
reMap
v4.2.6 vom 23.07.2021
3,34700,554
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,69020,515
ModelMapper
v3.1.0 vom 08.03.2022
6,35870,561

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 11 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.5 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Version Dozer vom 09.01.2022 (v1.5.5, jdk11-04)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01210,109
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00680,082
MapStruct
v1.4.2.Final vom 31.01.2021
0,01360,117
Orika
v1.5.4 vom 20.02.2019
0,29610,458
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39270,492
reMap
v4.2.6 vom 23.07.2021
3,07610,317
Dozer
v6.5.2 vom 07.04.2021
Anmerkungen
5,84070,427
ModelMapper
v3.0.0 vom 05.01.2022
6,26940,512

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 11 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Version von Mappern vom 05.01.2022 (v1.5.4, jdk11-03)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01360,120
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00660,081
MapStruct
v1.4.2.Final vom 31.01.2021
0,01440,119
Orika
v1.5.4 vom 20.02.2019
0,28930,456
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39500,494
reMap
v4.2.6 vom 23.07.2021
3,13890,382
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
4,33250,495
ModelMapper
v3.0.0 vom 05.01.2022
6,59450,563

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 11 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Neu: OpenJDK vom 04.01.2022 (v1.5.3, jdk11-02)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01380,117
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00650,080
MapStruct
v1.4.1.Final vom 11.10.2020
0,01510,123
Orika
v1.5.4 vom 20.02.2019
0,26220,441
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39130,489
reMap
v4.2.5 vom 31.07.2020
3,23750,461
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
4,29330,470
ModelMapper
v2.3.9 vom 20.11.2020
5,86450,431

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 11 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 20.04.3 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Neu: Java 11 vom 03.01.2021 (v1.5.2, jdk11-01)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,01130,105
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00610,078
MapStruct
v1.4.1.Final vom 11.10.2020
0,01300,113
Orika
v1.5.4 vom 20.02.2019
0,25720,442
Selma
v1.0 vom 01.05.2017
Anmerkungen
0,39130,489
reMap
v4.2.5 vom 31.07.2020
3,11770,346
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
4,10550,347
ModelMapper
v2.3.9 vom 20.11.2020
5,66160,543

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 11 (64 Bit, AdoptOpenJDK Hotspot)
  • Linux Ubuntu 64 Bit 20.04.1 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mappern vom 02.01.2021 (v1.5.1, jdk8-11)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,00850,093
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
Anmerkungen
0,00660,083
MapStruct
v1.4.1.Final vom 11.10.2020
0,01440,121
Orika
v1.5.4 vom 20.02.2019
0,23860,431
Selma
v1.0 vom 01.05.2017
0,51180,505
reMap
v4.2.5 vom 31.07.2020
3,71050,584
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
4,99840,371
ModelMapper
v2.3.9 vom 20.11.2020
5,18500,531

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, AdoptOpenJDK Hotspot)
  • Linux Ubuntu 64 Bit 20.04.1 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: Neu: Rechner, Betriebssystem vom 30.12.2020 (v1.5.0, jdk8-10)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,00930,098
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
0,00720,085
MapStruct
v1.3.1.Final vom 29.09.2020
0,01330,117
Orika
v1.5.4 vom 20.02.2019
0,24350,434
Selma
v1.0 vom 01.05.2017
0,50400,509
reMap
v4.2.5 vom 31.07.2020
3,72070,618
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
5,04280,416
ModelMapper
v2.3.8 vom 05.06.2020
5,11710,479

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, AdoptOpenJDK Hotspot)
  • Linux Ubuntu 64 Bit 20.04.1 LTS
  • Desktop-Rechner
  • Speicher 64 GB
  • Prozessor AMD® Ryzen 9 3950x 16-core processor × 32
  • Grafik NVIDIA Corporation TU104 [GeForce RTX 2070 SUPER]

Aktualisierung der Messung: neue Versionen von Mappern vom 02.08.2020 (v1.4.4, jdk8-09)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0260,158
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
0,0150,121
MapStruct
v1.3.1.Final vom 29.09.2020
0,0510,221
Orika
v1.5.4 vom 20.02.2019
0,5020,507
Selma
v1.0 vom 01.05.2017
0,6370,508
reMap
v4.2.5 vom 31.07.2020
7,5440,822
ModelMapper
v2.3.8 vom 05.06.2020
10,7561,078
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
12,1611,431

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, AdoptOpenJDK Hotspot)
  • Linux Ubuntu 64 Bit 18.04.4 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Aktualisierung der Messung: Neu: Mapper, Betriebsystem, JDK vom 07.06.2020 (v1.4.3, jdk8-08)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0210,150
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
0,0250,160
MapStruct
v1.3.0.Final vom 10.02.2019
0,0620,248
Orika
v1.5.4 vom 20.02.2019
0,5290,534
Selma
v1.0 vom 01.05.2017
0,7920,459
reMap
v4.1.5 vom 06.02.2019
2,9680,609
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
12,0261,282
ModelMapper
v2.3.2 vom 26.11.2018
36,1582,507

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, AdoptOpenJDK Hotspot)
  • Linux Ubuntu 64 Bit 18.04.4 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Aktualisierung der Messung: neue Versionen von Mappern vom 10.12.2018 (v1.4.2, jdk8-07)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0210,156
JMapper Framework
v1.6.1.CR2 vom 14.12.2016
0,0260,162
MapStruct
v1.2.0.Final vom 17.10.2017
0,2290,423
Orika
v1.5.2 vom 06.10.2017
0,5480,530
Selma
v1.0 vom 01.05.2017
0,7830,466
reMap
v4.1.1 vom 08.11.2018
3,0690,591
Dozer
v5.5.1 vom 22.04.2014
Anmerkungen
11,9531,288
ModelMapper
v2.3.2 vom 26.11.2018
41,2522,821

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 18.04.1 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Aktualisierung der Messung: Neu: Betriebssystem, OpenJDK vom 05.12.2018 (v1.4.1, jdk8-06)

Keine Änderungen an den Mappern
Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0180,136
JMapper Framework (v1.6.1.CR2)0,0190,137
MapStruct (v1.2.0.CR2)0,2070,409
Orika (v1.5.1)0,5240,519
Selma (v1.0)0,7880,467
reMap (v1.0.3)3,1930,531
ModelMapper (v1.1.0)7,0551,031
Dozer (v5.5.1)11,6841,193

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 18.04.1 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Update des Beitrags mit reMap vom 05.10.2017 (v1.4.0, jdk8-05)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0180,134
JMapper Framework (v1.6.1.CR2)0,0190,138
MapStruct (v1.2.0.CR2)0,1810,390
Orika (v1.5.1)0,5150,538
Selma (v1.0)0,7860,470
Neu: reMap (v1.0.3)2,9400,649
ModelMapper (v1.1.0)7,1021,114
Dozer (v5.5.1)11,5182,255

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, ORACLE)
  • Linux Ubuntu 64 Bit 14.04.05 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Update des Beitrags mit Selma vom 03.04.2017 (v1.3.0, jdk8-04)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0170,134
JMapper Framework (v1.6.1.CR2)0,0160,129
MapStruct (v1.2.0.Beta2)0,1790,393
Orika (v1.5.0)0,5360,527
Neu: Selma (v0.15)0,7760,454
ModelMapper (v0.7.8)6,9301,113
Dozer (v5.5.1)11,3151,244

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, ORACLE)
  • Linux Ubuntu 64 Bit 14.04.05 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Update des Beitrags mit JMapper Framework vom 27.05.2016 (v1.2.3, jdk8-03)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0160,133
Neu: JMapper Framework (v1.6.0.1)0,0150,123
MapStruct (v1.0.0.Final)0,1730,388
Orika (v1.4.6)0,5310,557
ModelMapper (v0.7.5)5,6240,964
Dozer (v5.5.1)11,1381,325

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, ORACLE)
  • Linux Ubuntu 64 Bit 14.04.04 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Update des Beitrags mit ModelMapper vom 28.03.2016 (v1.1.0, jdk8-02)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0230,163
MapStruct (v1.0.0.Final)0,1610,368
Orika (v1.4.6)0,5340,526
Neu: ModelMapper (v0.7.5)5,6240,956
Dozer (v5.5.1)11,2201,137

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, ORACLE)
  • Linux Ubuntu 64 Bit 14.04.04 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Erstellung des Beitrags am 19.07.2015 (v1.0.0, jdk8)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0160,144
MapStruct (v1.0.0.Beta4)0,1520,372
Orika (v1.4.5)0,5140,534
Dozer (v5.5.1)10,3711,152

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 8 (64 Bit, ORACLE)
  • Linux Ubuntu 64 Bit 14.04.01 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Test am 02.08.2014 (Commit 739903, jdk7)

Arithmetischer MittelwertStandardabweichung
ByHand (v1.0)0,0190,147
MapStruct (v1.0.0.Beta2)0,2850,458
Orika (v1.4.5)0,5290,547
Dozer (v5.5.1)10,2921,146

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 7 (64 Bit, OpenJDK)
  • Linux Ubuntu 64 Bit 14.04 LTS
  • Desktop-Rechner
  • Speicher 12 GB
  • Prozessor Intel Core i7 CPU 975 @ 3,33 GHz * 8

Test am 04.07.2014 (Commit FCC6F9, jdk6)

Mittelwert
ByHand (v1.0)0,071
MapStruct (v1.0.0.Beta2)0,853
Orika (v1.4.5)2,328
Dozer (v5.5.1)46,259

Unter den folgenden Rahmenbedingungen wurde dieser Test durchgeführt.

  • Java Version 6 (32 Bit, Oracle)
  • Windows 7 Enterprise 64 Bit ServicePack 1
  • VDI (virtueller Desktop)
  • Speicher 4 GB
  • Prozessor Intel Xeon CPU ES-2670 @ 2.60 GHz 2.59 GHz

 
Alle Tests, mit den unterschiedlichen Rahmenbedingungen, sind im GitHub-Verzeichnis zu finden.

Excel Arbeitsmappe: Das zweite Tabellenblatt enthält die Messwerte. Auf dem ersten Tabellenblatt sind die Messwerte des Einschwingvorgangs.

Die Maven-Befehle zur Durchführung der Tests befinden sind in diesem Kapitel Durchführen der Messungen beschrieben.

Die Umfragen

Umfrage vom 07.04.2017 bis zum 31.07.2017

Wer ist Ihr bevorzugter Java Bean Mapper?

  • MapStruct (28%, 11 Stimmen)
  • Dozer (21%, 8 Stimmen)
  • ByHand (15%, 6 Stimmen)
  • JMapper (15%, 6 Stimmen)
  • ModelMapper (10%, 4 Stimmen)
  • Orika (5%, 2 Stimmen)
  • Spring Framework BeanUtils (3%, 1 Stimmen)
  • Selma (3%, 1 Stimmen)
  • Apache Commons BeanUtils (0%, 0 Stimmen)

Teilnehmerzahl: 39 (1 Stimmen)

Wird geladen ... Wird geladen ...

Die Umfrage wurde am 31.07.2017 beendet. Diesmal gab es einen eindeutigen Sieger:
MapStruct mit 11 Stimmen vor Dozer mit 8 Stimmen. Herzlichen Glückwunsch!

Umfrage vom 19.07.2015 bis zum 19.10.2015

Wie schon geschrieben, verwende ich vor allem MapStruct. Wie ist das bei Euch?

Wer ist Ihr bevorzugter Java Bean Mapper?

  • Dozer (33%, 3 Stimmen)
  • Orika (33%, 3 Stimmen)
  • MapStruct (33%, 3 Stimmen)
  • Spring Framework BeanUtils (0%, 0 Stimmen)
  • Apache Commons BeanUtils (0%, 0 Stimmen)
  • ByHand (0%, 0 Stimmen)

Teilnehmerzahl: 9 (1 Stimmen)

Wird geladen ... Wird geladen ...

Die Umfrage wurde am 19.10.2015 beendet. Diese Umfrage ging unentschieden zwischen Dozer, Orika und MapStruct mit jeweils 3 Stimmen aus.

 
Der Quellcode und Download

Quellcode ansehen bei GitHub:
Java Bean Mapper

Download einer ZIP-Datei von GitHub:
Java Bean Mapper

Die Maven Befehle

Eclipse Konfiguration neu erzeugen: $ mvn eclipse:clean eclipse:eclipse

Es wird das Eclipse Plug-in M2Eclipse verwendet.

Die Anwendungen bauen: $ mvn clean install

Durchführen der Messungen

Auf der Konsole in das Root-Verzeichnis des Projektes wechseln und die folgenden Befehle ausführen.

$ mvn clean install
$ cd bean-mapper-test/
$ mvn -Dtest=PerformanceTestWithCompleteFixtures test
$ mvn -Dtest=PerformanceTestWithIncompleteFixtures test
  • Über
  • Letzte Artikel
Frank Rahn
Frank Rahn
Frank Rahn ist Softwarearchitekt. Er unterstützt bei der Konzeption von Softwarearchitekturen mit Java-Technologie. Folge Sie ihm auf Facebook oder Twitter.

Benötigen Sie Unterstützung? Kontaktieren Sie ihn.

Hat Ihnen dieser Beitrag gefallen? Wir würden uns über Ihren Kommentar freuen! Bitte verwenden Sie Ihren bürgerlichen Namen.
Frank Rahn
Letzte Artikel von Frank Rahn (Alle anzeigen)
  • Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
  • Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
  • Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
39 Kommentare/von Frank Rahn
Schlagworte: Java, Java SE, JPA, Spring, Webservice, XML-Schema
Eintrag teilen
  • Teilen auf X
  • Teilen auf WhatsApp
  • Teilen auf LinkedIn
  • Per E-Mail teilen
  • Teilen auf Xing
https://www.frank-rahn.de/wp-content/uploads/BeanMapper-am-Beispiel-ByHand.png 1044 1934 Frank Rahn /wp-content/uploads/logo.png Frank Rahn2023-09-22 20:59:552026-02-16 15:26:52Wer ist der optimale Java Bean Mapper?
Das könnte Dich auch interessieren
Die REST-API des Webservice der Fahrerverwaltung Spring mit RESTful Webservice (Tutortial)
Spring Boot Webanwendung Spring Boot Webanwendung: Die ersten Schritte (Tutorial)
LegStar modules for z/OS Mainframe-Zugriff via Java
Die Stored Procedure "searchPersons" mit User-defined Types (UDT) Spring und Stored Procedure mit User-defined Types (Tutorial)
Die ApplicationContexte einer einfachen Spring Webanwendung Spring mit einer einfachen Webanwendung (Tutorial)
Dieses Bild zeigt meinen IT-Werkzeugkasten Franks aktueller IT-Werkzeugkasten
39 Kommentare
  1. Felix
    Felix sagte:
    Montag, 27. April 2026 um 16:38 Uhr

    Oh, vielen Dank – jetzt weiß ich auch, wie ich meinen alten Mapper weiterbenutzen kann.

    Reply
  2. Frank Rahn
    Frank Rahn sagte:
    Dienstag, 11. Oktober 2022 um 19:58 Uhr

    Es gab einige Anfragen, ob ich Java 17 berücksichtigen kann. Da gibt es leider ein paar Probleme. Nicht alle Mapper kompilieren unter JDK 17. Die folgenden beiden Exceptions treten dabei auf:

    java.lang.reflect.InaccessibleObjectException : Unable to make field <field> accessible: module <xxx> does not "opens <yyy>" ...

    java.lang.reflect.InaccessibleObjectException : Unable to make <methode> accessible: module <xxx> does not "opens <yyy>" ...

    Das betraf die Mapper: Orika, JMapper Framework und reMap.

    Natürlich kann ich diese Mapper aus dem Test herausnehmen. Was beim JMapper womöglich geschehen wird, da dieser Mapper nicht mehr weiterentwickelt wird. Andere Mapper haben eine Anpassung angekündigt (reMap).

    EDIT: reMap hat den Fehler in der Version 4.3.0 gefixt!

    Es können auch VM Optionen gesetzt werden:
    --add-opens=<xxx>/<yyy>=ALL-UNNAMED

    Ich weiß nicht, ob das eine tragfähige Lösung ist. Was meint ihr?

    Ende November kommt Spring Boot 3 mit Spring Framework 6, welches auf das JDK 17 aufsetzt. Da müssten die Mapper eigentlich nachziehen, damit die Nutzer umstellen können.

    EDIT: Ich hab schon mal den Branch java-17 bereitgestellt, falls jemand mit JDK 17 spielen möchte. Die Änderungen wurden in den Branch master zusammengeführt.

    Viele Grüße
    Frank

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Montag, 05. Dezember 2022 um 18:11 Uhr

      Orika

      Fehler:
      java.lang.reflect.InaccessibleObjectException: Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not "opens java.lang" to unnamed module

      JVM Optionen:
      --add-opens=java.base/java.lang=ALL-UNNAMED

      Reply
    • Frank Rahn
      Frank Rahn sagte:
      Dienstag, 06. Dezember 2022 um 18:23 Uhr

      JMapper Framework

      Fehler:
      java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module

      java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Comparator java.util.TreeMap.comparator accessible: module java.base does not "opens java.util" to unnamed module

      java.lang.reflect.InaccessibleObjectException: Unable to make field protected java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.h accessible: module java.base does not "opens java.lang.reflect" to unnamed module

      java.lang.reflect.InaccessibleObjectException: Unable to make protected java.lang.String java.text.AttributedCharacterIterator$Attribute.getName() accessible: module java.base does not "opens java.text" to unnamed module

      java.lang.reflect.InaccessibleObjectException: Unable to make field private static final java.util.Map java.awt.font.TextAttribute.instanceMap accessible: module java.desktop does not "opens java.awt.font" to unnamed module

      Alle Fehler werden durch die Bibliothek XStream ausgelöst.

      JVM Optionen:
      --add-opens=java.base/java.lang=ALL-UNNAMED

      --add-opens=java.base/java.util=ALL-UNNAMED

      --add-opens=java.base/java.lang.reflect=ALL-UNNAMED

      --add-opens=java.base/java.text=ALL-UNNAMED

      --add-opens=java.desktop/java.awt.font=ALL-UNNAMED

      Reply
    • Frank Rahn
      Frank Rahn sagte:
      Mittwoch, 07. Dezember 2022 um 18:27 Uhr

      reMap

      Fehler:
      java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module

      Der Fehler werden durch das Tool CGLIB ausgelöst.

      JVM Optionen:
      --add-opens=java.base/java.lang=ALL-UNNAMED

      EDIT: Dieser Fehler wurde in der Version 4.3.0 gefixt.

      Reply
      • Frank Rahn
        Frank Rahn sagte:
        Montag, 21. Juli 2025 um 20:11 Uhr

        Der folgende Fehler trat mit der Umstellung auf Java 21 auf:
        java.lang.UnsupportedOperationException: Cannot define class using reflection: Unable to make protected java.lang.Package java.lang.ClassLoader.getPackage(java.lang.String) accessible: module java.base does not "opens java.lang" to unnamed module

        JVM Optionen:
        --add-opens=java.base/java.lang=ALL-UNNAMED

        Reply
  3. Jukka Nikki
    Jukka Nikki sagte:
    Donnerstag, 24. Januar 2019 um 13:24 Uhr

    Beeindrückende artikel. Ich frage mich ob Smooks würde qualifizieren für mapper hier? Ich habe smooks benutzt eher für xml -> javabean, und da ist es ja auch gut. Smooks ist nicht aktiv weiterentwickelt, aber ist schon ein etablierten über 10 jahte alte library.

    http://nikkijuk.blogspot.com/2013/08/simple-xml-to-jpa-data-service-with.html

    Reply
  4. Denny
    Denny sagte:
    Dienstag, 03. Juli 2018 um 11:23 Uhr

    Hallo,

    vielen Dank für diesen ausführlichen Vergleich.
    Ist euch vielleicht ein Framework bekannt, welches ähnlich dem EqualsBuilder von Apache Commons funktioniert, jedoch 2 Objekte unterschiedlicher Typen miteinander vergleichen kann? Quasi als Prüfung ob ein Mapper korrekt funktioniert hat und alle Felder berücksichtigt hat.

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Mittwoch, 04. Juli 2018 um 18:57 Uhr

      Nein, im Moment fällt mir da nichts ein. Ich hab immer JUnit-Test geschrieben, falls so eine Prüfung notwendig war.

      Viele Grüße
      Frank

      Reply
  5. C. Schütte
    C. Schütte sagte:
    Donnerstag, 21. September 2017 um 8:58 Uhr

    Hallo, vielen Dank für diesen ausführlichen Artikel!

    Eine weitere interessante Mapping Library ist ReMap (https://github.com/remondis-it/remap). Dieser Mapper unterstützt als einziger einen komfortablen Weg, ein Objekt-Mapping zu testen. Für Regressionstests ist dies ein wichtiges Feature. Des Weiteren vermeidet dieser Mapper, das Code angepasst werden muss (wie z.B. bei Lösungen mit Annotations).

    Vielleicht wäre diese Bibliothek auch ein guter Kandidat für diesen Artikel 🙂

    Reply
    • Tom Hombergs
      Tom Hombergs sagte:
      Sonntag, 01. Oktober 2017 um 22:25 Uhr

      Spannender Vergleich der Mapper! Vielen Dank dafür.

      Ich war an der Performance von unserem Mapper reMap interessiert und habe bei der Gelegenheit einen Pull Request erstellt, in dem reMap in das Test-Framework aufgenommen wurde (https://github.com/frank-rahn/performance/pull/1). Würde mich auch freuen, wenn der Mapper hier noch aufgenommen wird 🙂

      Ein paar weitergehende Infos zu diesem Mapper gibt es auch im folgenden Blog-Artikel: https://reflectoring.io/autotmatic-refactoring-safe-java-mapping/

      Viele Grüße,
      Tom

      Reply
      • Frank Rahn
        Frank Rahn sagte:
        Montag, 02. Oktober 2017 um 18:08 Uhr

        Hallo Tom!

        Ein Pull Request? Cool! 🙂 Da gebe ich mich mal dran …

        Vielen Dank und Grüße,
        Frank

        Reply
      • Frank Rahn
        Frank Rahn sagte:
        Mittwoch, 04. Oktober 2017 um 22:08 Uhr

        Hallo Tom,

        ich habe den Pull Request in das Test-Framework aufgenommen und den Mapper in die Seite integriert.

        Vielen Dank für den Request und viele Grüße,
        Frank

        Reply
        • Tom Hombergs
          Tom Hombergs sagte:
          Freitag, 06. Oktober 2017 um 11:41 Uhr

          Danke dir!

          Gruß,
          Tom

          Reply
    • Frank Rahn
      Frank Rahn sagte:
      Mittwoch, 04. Oktober 2017 um 22:10 Uhr

      Ich hab den Mapper aufgenommen.

      Vielen Dank für die Anregung.

      Viele Grüße,
      Frank

      Reply
  6. Wolfgang Häfelinger
    Wolfgang Häfelinger sagte:
    Samstag, 06. Mai 2017 um 16:29 Uhr

    Wie sieht es mit zwei weiteren typischen Problemen aus?
    a) No Contructor: Beispiel XMLGregorianCalendar LocalDate
    b) „Coded Enum“, i.e. enum ANREDE { HERR(„01“), FRAU(„02“), UNBEKANNT(„03); … } String
    Wie gut können die Mapper-Frameworks damit umgehen? Wie aufwändig sind „Custom Converter“ zu integrieren?

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Sonntag, 28. Mai 2017 um 19:52 Uhr

      Beispiele für Custom Converter sind in den folgenden Packages implementiert:

      • de.rahn.performance.beanmapper.vendors
      • de.rahn.performance.beanmapper.selma
        Für den Mapper Selma die Converter DateCustomMapper und CustomCalendar.
      • de.rahn.performance.beanmapper.mapstruct
        Mapper JMapper
        In der Klasse JMapperTestBeansMapperBean ab Zeile 44.

        Bei den Mapper MapStruct kann anstatt das Mapper Interface auch eine abstrakte Klasse verwendet werden, die dann Methode zur Konvertierung implementiert.

      Bei den modernen Mappern sind die Unterstützungen recht ausgereift.

      Reply
  7. schlegel11
    schlegel11 sagte:
    Sonntag, 23. April 2017 um 16:28 Uhr

    Interessantes Thema.
    Ich selbst, habe erst vor kurzem, Mappings von einer XML Datei, auf verschiedene Entitäten durchführen müssen.
    Was ich dabei immer schwierig finde, ist quasi einen Adapter zu schreiben, der sowohl das Mappen, als auch die Validierung übernehmen kann. Gerade wenn man nicht auf einen DOM Parser setzen kann.
    Dabei komme ich meistens nicht drum herum, eine Implementierung von Hand vor zu nehmen.
    Eventuell müsste man sich mal für solche Fälle einen eigenen Generator schreiben.

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Sonntag, 23. April 2017 um 17:28 Uhr

      Falls es für die XML ein XSD Schema gibt, kann ein JAXB Generator verwendet werden. Mittlerweile sind diese Konverter ganz gut. Für eine komplexe Validierung kann die Bean Validation JSR-303 oder die Validatoren von Spring verwendet werden. Hibernate (org.hibernate:hibernate-validator:5.3.5.Final) hat da eine gute JSR-303 v1.1 Implementierung.

      Reply
      • schlegel11
        schlegel11 sagte:
        Sonntag, 23. April 2017 um 19:58 Uhr

        Genau das wäre ein guter weg gewesen. Leider existiert kein XSD Schema bzw. liegt nicht weiter vor.
        Des Weiteren ist die XML recht groß bzw. wusste ich nicht genau ob JAXB eine SAX oder DOM Implementierung nutzt, wobei hier die DOM Variante zu langsam gewesen wäre.
        Jetzt benutze ich hier pro Entität einen Adapter, welcher quasi etwas unkonventionell die Methoden dieser nochmals abbildet bzw. im Grunde die setter Methoden. Die einzelnen XML Attribute, werden dann als String Objekte übergeben und von der jeweiligen Methode validiert und in den spezifischen Typ umgewandelt bzw. in den, welcher von der Entität erwartet wird.
        Das ist leider etwas mehr Aufwand, wobei der Vorteil darin liegt überall direkt eingreifen zu können. Aber ja JAXB wäre in dem Fall einfacher gewesen.

        Reply
        • Frank Rahn
          Frank Rahn sagte:
          Montag, 24. April 2017 um 13:00 Uhr

          Vielleicht ist ein Blick auf die Streaming API for XML (JSR-173) hilfreich oder interessant.

          Die StAX-API bietet den Zugriff auf die XML-Daten über einen Cursor an XMLStreamReader, der auf eine Stelle (Element) im Dokument zeigt und durch die Anwendung mit (next()) weiter bewegt wird. Alternativ kann auch mit einem Iterator-Verfahren XMLEventReader gearbeitet werden. Durch den Pull-Ansatz sollte die Implementierung etwas lesbarer werden – ggf. kann dieses mit JAXB kombiniert werden.

          Reply
          • schlegel11
            schlegel11 sagte:
            Montag, 24. April 2017 um 23:41 Uhr

            Ah Interessant. Ich werde mir StAX bzw. auch den „hibernate-validator“
            mal anschauen. Leider stecke ich noch nicht so richtig in der JEE Welt drinne 😉 Aber Vielen Dank schon mal für die tolle Hilfe und den guten Artikel 🙂

          • Frank Rahn
            Frank Rahn sagte:
            Dienstag, 25. April 2017 um 9:07 Uhr

            Vielen Dank

  8. Peter
    Peter sagte:
    Dienstag, 14. März 2017 um 9:52 Uhr

    Hi,

    es wäre cool wenn du noch http://www.selma-java.org/ mit aufnehmen könntest.

    LG
    Peter

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Samstag, 01. April 2017 um 13:45 Uhr

      Bin dabei 🙂

      Reply
    • Frank Rahn
      Frank Rahn sagte:
      Freitag, 07. April 2017 um 13:25 Uhr

      Erledigt!

      Reply
  9. Urs Stuber
    Urs Stuber sagte:
    Dienstag, 02. August 2016 um 13:59 Uhr

    Vielen Dank für Ihre Zusammenstellung!

    Welche Mapper würden Sie aktuell einer Firma guten Gewissens empfehlen im Hinblick auf die weitere Pflege? Mich irritiert beim Blick ins gitHub, dass sowohl bei Orika wie bei Dozer die meiste Entwicklung im Jahr 2013 stattfand und in letzter Zeit kaum noch Weiterentwicklungen / Bugfixes zu finden sind und keine neue Releases mehr herauskamen. Denken Sie, dass diese Mapper weiterhin gewartet werden oder ist zu befürchten, dass wenn man jetzt grösseren Entwicklungsaufwand in die Erstellung von mappings mit diesen Tools steckt, man in einer Sackgasse landen könnte („never ride a dead horse“)?

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Dienstag, 02. August 2016 um 18:40 Uhr

      Ich würde aktuell entweder das JMapper Framework oder MapStruct verwenden.

      Bei MapStruct wird es demnächst die Version 1.1.0 geben – diese ist im Moment im Beta-Test.

      Der ModelMapper wird zur Zeit mäßig entwickelt. Bei den anderen Mappern sieht es düster aus. Wobei bei Dozer aber auch ein sehr hoher Reifegrad erreicht wurde. Der Dozer ist aber auch der häufigste genutzte und älteste Mapper.

      Reply
  10. Alessandro Vurro
    Alessandro Vurro sagte:
    Dienstag, 12. April 2016 um 15:11 Uhr

    It would be interesting to see how JMapper competes with the technologies you mentioned (i’m the founder).

    https://github.com/jmapper-framework/jmapper-core

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Sonntag, 08. Mai 2016 um 17:58 Uhr

      Ich hab den JMapper hinzugefügt. Er hat eine beeindruckende Performanz – er kann mit der Geschwindigkeit des Mappers ByHand mithalten.

      Reply
      • Alessandro Vurro
        Alessandro Vurro sagte:
        Donnerstag, 12. Mai 2016 um 11:31 Uhr

        thank you for adding JMapper between the java bean mappers.
        However, you can switch destination and source positions without rewrite the configuration, obviously if the relationship is the same:

        ...
        	@PostConstruct
        	public void initialize() {
        		JMapperAPI jMapperAPI = new JMapperAPI()
        			.add(mappedClass(...)
        				.add(conversion("dateToCalendar").from("date").to("date")
        					.body("java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(${source}); return c;")))
        				.add(conversion("calendarToDate").from("date").to("date")
        					.body("return ${source}.getTime();"))
        			.add(mappedClass(...));
        		domainToXmlMapper = new JMapper(XmlTable.class, DomainTable.class, jMapperAPI);
        		xmlToDomainMapper = new JMapper(DomainTable.class, XmlTable.class, jMapperAPI);
        	}
        ...

        If you want to avoid creating multiple instances of JMapper you should use RelationalJMapper.

        Reply
        • Frank Rahn
          Frank Rahn sagte:
          Freitag, 27. Mai 2016 um 21:56 Uhr

          Ich habe die Klasse JMapperTestBeansMapperBean entsprechend angepasst.

          Reply
  11. Lukas Eder
    Lukas Eder sagte:
    Mittwoch, 28. Oktober 2015 um 11:44 Uhr

    ModelMapper wäre auch noch eine erwähnenswerte Alternative…

    Reply
    • Frank Rahn
      Frank Rahn sagte:
      Montag, 28. März 2016 um 19:03 Uhr

      Ich habe den ModelMapper hinzugefügt. Er liegt von der Performanz hinter Orika. Da er aktuell noch entwickelt wird, muss man sehen wie er sich entwickelt.

      Sorry für die verspätete Umsetzung 🙁 Beim nächsten Mapper werde ich schneller sein – versprochen!

      Reply
      • Ralf Treuherz
        Ralf Treuherz sagte:
        Mittwoch, 01. Februar 2017 um 9:38 Uhr

        Die Werte in der Tabelle zu ModelMapper sind um den Faktor 10 zu hoch angegeben.
        Es müssten 0.5624 ms sein, statt 5,624, wie angegeben

        Reply
        • Frank Rahn
          Frank Rahn sagte:
          Mittwoch, 01. Februar 2017 um 19:44 Uhr

          Die Werte in der Tabelle wurden aus dem Excel-Sheet (Zum Excel-Sheet bei Git-Hub), welches bei der Messung geschrieben wird, abgelesen.

          Der Wert für den arithmetischen Mittelwert des ModelMappers befindet sich in der Zelle F7 in der Tabelle Performanz Messung.

          Wie kommen Sie auf den Faktor 10?

          Reply
          • Ralf Treuherz
            Ralf Treuherz sagte:
            Donnerstag, 02. Februar 2017 um 10:21 Uhr

            1) Die Aussage „Dieser Mapper ähnelt den schon vorher beschriebenen Mappern Orika und Dozer und sortiert sich auch entsprechend mit der Performanz ein.“ bezüglich ModelMapper scheint den Messergebnissen nicht zu entsprechen ( 0,531 ms für Orika vs. 5,624 ms für ModelMapper)
            2) Eigene Tests mit komplexen Objektstrukturen unterstützen die Performanz von ModelMapper, hier habe ich um die 0.5 ms gemessen.
            3) Eine Messung mit Ihrer Testsuite habe ich selber nicht vorgenommen, Wenn diese tatsächlich einen Performance-Unterschied den Faktor 10 von Orika gegenüber ModelMapper zeigt, ist die Aussage in 1) zumindest irreführend.

          • Frank Rahn
            Frank Rahn sagte:
            Sonntag, 05. Februar 2017 um 23:43 Uhr

            Zu 3) und 1), ich werde diese Aussage ändern, so dass sie klarer wird.
            Zu 2) würde mich interessieren welche Versionen (ModelMapper, JDK, etc.) sie verwenden.

          • Frank Rahn
            Frank Rahn sagte:
            Samstag, 01. April 2017 um 20:38 Uhr

            Ich habe den Text nun überarbeitet. Ich habe zufällig gesehen, das sich die Version von ModelMapper und einige anderen Mappern erhöht haben. Ich werden die TestSuit aktualisieren.

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar Antwort abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Ihre E-Mail-Adresse wird nicht veröffentlicht. Ihr Kommentar wird verschlüsselt an meinen Server gesendet. Erforderliche Felder sind mit * markiert.

Weitere Informationen und Widerrufshinweise finden Sie in meiner Datenschutzerklärung.

Wollen Sie kein neuen Beiträge mehr verpassen?
Dann abonnieren Sie bitte meinen Newsletter.
Meinen Newsletter abonnieren

Themen

  • Wer ist der optimale Java Bean Mapper?
  • Einführung in das Spring Framework, Boot, Batch, Data, REST, Security, Web, …
  • Franks aktueller IT-Werkzeugkasten
  • Git, GitHub, EGit, …

Navigation

  • Buchtipps
  • Newsletter
  • Weblinks
Search Search

Werbung

  • JProfiler
Beliebt
  • Das Klassendiagramm für den Java Bean Mapper Test am Beispiel "ByHand"
    Wer ist der optimale Java Bean Mapper?Freitag, 22. September 2023 - 20:59 Uhr
  • Das offizielle Logo von EGit
    GitHub mit Eclipse (EGit)Freitag, 26. Oktober 2012 - 16:15 Uhr
  • Grobe Übersicht üder den Spring Framework Container
    Einführung in das Spring FrameworkSonntag, 01. Mai 2011 - 18:30 Uhr
  • Die Stored Procedure "searchPersons" mit User-defined Types (UDT)
    Spring und Stored Procedure mit User-defined Types (Tut...Freitag, 26. Oktober 2012 - 21:45 Uhr
  • Spring Boot Webanwendung
    Spring Boot Webanwendung: Die ersten Schritte (Tutorial...Montag, 28. März 2016 - 16:29 Uhr
Schlagworte
Annotations AOP Architektur Autorisierung Cookies CRUD DAO DI Git HTML HTTP IoC Java Java EE Java SE JPA JSR Linux MVC Open Source Software PDF POJO REST (RESTful) ROCA Self-contained Systems Serviceorientierte Shell Sicherheit (Security) SOAP Spring SQL SVN Test Toolchain URI URL URN User-defined Type Versionsverwaltung VPN Webservice WS-* WSDL XML XML-Schema

Blogarchiv

Links

Mastodon
Twitter
LinkedIn
Xing
GitHub

Lizenz

Creative Commons Lizenzvertrag Die Texte (nicht Bilder) von Frank Rahn stehen unter einer Creative Commons Namensnennung - Keine Bearbeitungen 4.0 Deutschland Lizenz.

Affiliate-Links

Die mit (*) gekennzeichnete Links sind sogenannte Affiliate-Links. Kommt über einen solchen Link ein Einkauf zustande, werde ich mit einer Provision beteiligt. Für Sie entstehen dabei keine Mehrkosten. Wo, wann und wie Sie ein Produkt kaufen, bleibt natürlich Ihnen überlassen.

Blogkategorien

Copyright © Frank W. Rahn
  • Impressum / HaftungsausschlussDie notwendigen gesetzlichen Angaben dieser Webseite von Frank Rahn
  • DatenschutzerklärungDie Datenschutzerklärung von Frank Rahn
  • NewsletterKeine neuen Beiträge mehr verpassen!
  • BildnachweisDer komplette Bildnachweis von Frank Rahn
Link to: Spring Boot Webanwendung: Die ersten Schritte (Tutorial) Link to: Spring Boot Webanwendung: Die ersten Schritte (Tutorial) Spring Boot Webanwendung: Die ersten Schritte (Tutorial)Spring Boot Webanwendung
Nach oben scrollen Nach oben scrollen Nach oben scrollen

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden. Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

DatenschutzerklärungImpressumAlle Cookies akzeptierenKeine Cookies akzeptierenIndividuelle Cookie-Einstellungen vornehmen

Cookie- und Datenschutzeinstellungen



Wie wir Cookies verwenden

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden.

Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

Klicken Sie links auf die verschiedenen Reitern, um mehr zu erfahren. Sie können auch einige Cookie-Einstellungen individuell anpassen. Beachten Sie, dass das Blockieren einiger Cookies die einwandfreie Funktion unserer Webseite beeinträchtigt.

Technisch notwendige Cookies

Diese Cookies sind unbedingt erforderlich, denn sie ermöglichen grundlegende Funktionen und sind für die einwandfreie Funktion der Webseite erforderlich.

Sie können diese Cookies jederzeit blockieren oder löschen, indem Sie Ihre Browsereinstellungen ändern und die Blockierung aller Cookies auf dieser Webseite erzwingen. Leider werden Sie dann immer wieder gefragt, ob Sie Cookies akzeptieren oder ablehnen wollen, wenn Sie unsere Webseite erneut besuchen.

Wir setzen die Cookies aviaPrivacyEssentialCookiesEnabled, aviaPrivacyMustOptInSetting, aviaPrivacyRefuseCookiesHideBar und aviaCookieConsent ein, um Ihre individuellen Cookie-Einstellungen zu speichern. Diese Informationen geben wir an keinen Drittanbietern weiter.

Diese Cookies haben eine Laufzeit von einem Jahr, dann müssen Sie die Einstellungen wiederholen.

Die VG WORT setzt das Sitzungscookie srp zur Messung von Zugriffen auf Texten, um die Kopierwahrscheinlichkeit des Textes zu erfassen. Damit partizipieren ich an den Ausschüttungen der VG WORT, welche die gesetzliche Vergütung für die Nutzungen urheberrechtlich geschützter Werke gemäß § 53 UrhG sicherstellen. Das Cookie wird dazu verwendet, um den Nutzer zu identifizieren und ggf. Daten mehrerer Aufrufe von Texten miteinander verknüpfen zu können.

Nach Angaben der VG WORT stellt das eingesetzte Verfahren sicher, dass einzelne Nutzer oder ihr Leseverhalten nicht ermittelbar sind, wenn die Anzahl der Textaufrufe gezählt wird. Alle von der VG Wort erfassten Daten werden sofort sicher verschlüsselt. Der Einsatz des Zählpixels wurde durch das Bayerische Landesamt für Datenschutzaufsicht begutachtet und als datenschutzkonform bewertet.

Datenschutzerklärung der VG WORT

Marketing-Cookies

Die Marketing-Cookies werden von Drittanbietern oder Publishern, wie z. B. Google Analytics, verwendet, um personalisierte Werbung anzuzeigen. Sie tun dies, indem sie Besucher über Webseiten hinweg verfolgen (Tracking).

Wir setzen keine Marketing-Cookies ein.

Datenschutzbestimmungen

Sie können unsere Cookies und Datenschutzeinstellungen im Detail in unserer Datenschutzerklärung nachlesen.

Cookie-Einstellungen übernehmenKeine Cookies akzeptieren
Nachrichtenleiste öffnen Nachrichtenleiste öffnen Nachrichtenleiste öffnen