Zum Inhalt

mapstruct oder wie man DTOs vermeidet

Ich möchte hier ein paar Use-Cases für das Framework mapstruct vorstellen.


Das erste Use-Case ist: Vermeidung von DTOs

Die DTOs werden in der Regel dazu verwendet, um bestimmte interne Repräsentation der Daten (dazu gehören z.B. die technischen IDs) vor anderen Systemen zu verbergen. Das führt in der Regel zu solchen Konstrukten:

public class Person{
private Integer id;
private String firstName;
private String lastName;
private String email;
}

Und hier die dazu gehörende DTO Klasse:

public class PersonDto {
private String firstName;
private String lastName;
private String email;
}

Jetzt fehlt nur noch ein Konverter, manche schreiben/generieren auch einen Builder dazu und schon ist man fertig… ah ja, die Unittests müssen noch geschrieben werden, dann ist man fertig.

Und jetzt machen wir uns das Leben etwas einfacher! Wir löschen den Konverter/Builder, löschen die Tests, löschen die DTO Klasse und benutzen das oben erwähnte Framework mapstruct. Dazu ist es in der Regel vollkommen ausreichend folgendes zu tun:

@Mapper
public interface PersonMapper {

@Mapping(target="id", ignore = true)
Person map(Person source);
}

Wir haben erfolgreich, die Anzahl der getippten Codezeilen reduziert und damit (rein statistisch) die Anzahl der Bugs ;-).

Das zweite Use-Case: gleiche Klassen unterschiedliche Packages

Die Entwickler, die in großen Firmen viel mit Webservices arbeiten (ich nenne die Leute WSDL Opfer), kennen die Situation: Man hat aus der fachlichen Perspektive das gleiche Objekt das in zwei++ Webservices verwendet wird, aber der Enterprise Architekt oder auch Busyanalyst kennt nur seine Tools um die Webservices zu modellieren. Meistens sehr graphische Tools, die bequem zu nutzen sind. Das Ergebnis sieht, dann oft so aus (von mir start vereinfacht):

package service1.v23;

import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Address", propOrder = {
"streetLines",
})
public class Address {

@XmlElement(name = "StreetLines")
protected List<String> streetLines;

}
package service.very_importat.v1;

import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Address", propOrder = {
"streetLines",
})
public class Address {

@XmlElement(name = "StreetLines")
protected List<String> streetLines;

}

Die beiden Klassen sehen gleich aus, tun das gleiche und die Daten, die sie kapseln müssen diese untereinander austauschen können. Was in der Java Welt dazu führt: der Entwickler muss einen Konverter schreiben, der die Daten hin und her kopieren kann. Den drögen Code dazu lasse ich weg.

Die Lösung des Dilemmas: mapstruct.

@Mapper
public interface AddressMapper {

service.v23.Address copy(service.very_important.v1.Address source);

service.very_important.v1.Address copy(service.v23.Address source);
}

Fertig.

Use-Case drei: JPA und lazy loading

Dieses Use-Case ist ein weitergedachtes erstes Use-Case und tritt öfter bei klassischen “Datenbanken > < Rest-Schnittstelle” Projekten auf. Man möchten Daten aus einer Datenbank, die über JPA verfügbar sind, über eine Rest-Schnittstelle weitergeben. Wenn die Daten etwas komplexer ( 1:N Relationen z.B.) sind, dann hat schnell mit Lazy Loading zu tun. Und damit wieder mit DTOs.

Die Lösung sieht dann oft so aus, dass innerhalb einer Transaktion die Daten aggregiert und in die DTOs verpackt werden. Mit den DTOs kann man dann außerhalb der Transaktion weiter arbeiten.

Die Lösung mit mapstruct würde, dann so aussehen, dass der Mapper die Daten, die man über REST weitergeben möchte kopiert. Ich werde dazu keinen Beispielcode liefern (hab ich erwähnt, dass ich faul bin?). Diesen kann sich jeder Entwickler selbst überlegen.

Zum Schluss noch eine Preisfrage: habt ihr schon mal versucht Objekte in Java zu klonen?

Published inJavaProgrammierenUncategorized

Schreibe den ersten Kommentar

    Schreibe einen Kommentar

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

    Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.