WER ERZÄHLT DIE NÄCHSTEN 55+ MINUTEN
ETWAS?
Gerrit Brehmer, Karlsruhe
Auf der Arbeit: Software-Entwickler/Architekt ( / Pr...
BEAN-MAPPING: EINSATZ
Wann müssen Beans gemappt werden?
Entities zu DTOs
interne zu generierten Klassen (JAXB etc.)
zur Ei...
BEAN MAPPING: UMSETZUNG
Was benutzen wir dafür bisher?
von Hand geschriebener Mapping-Code
typsicher, schnell
fehleranfäll...
GEHT ES BESSER?
Wunschliste
schnell
typsicher
wenig Aufwand
automatisches Mapping
Null-Prüfungen
Konvertierungen von "ähnl...
MAPSTRUCT
mapstruct.org / github.com/mapstruct
OpenSource (Lizenz: Apache 2.0)
Initator & Maintainer: Gunnar Morling (RedH...
WIE FUNKTIONIERT MAPSTRUCT
Annotation Processor
Verarbeitet Annotations am eigenen Quellcode
siehe andere bekannte Libs: J...
DEMO
INTEGRATION IN ECLIPSE #1
MapStruct eclipse Plugin
noch work-in-progress
Hauptsächlich noch fehlende Features, keine Bugs
...
INTEGRATION IN ECLIPSE #2
m2e APT Plugin
Aktivierung nicht
vergessen!
Inkompatibilitäten mit
Eclipse Compiler pre Mars
(ab...
GENERIERTE ABHÄNGIGKEITEN
Zu mappende Klassen sind ebenfalls generiert (z.B. JAXB per Schema)
Resultat: Compiler Fehler be...
AUTOMAPPING #1
Primitive & Wrapper-Typen
Datums-Typen
Joda / Java 8 DateTime API Klassen
Date
Calendar
dest.setLocalDateTi...
AUTOMAPPING #2
Collection- & Array-Typen
Mapping nicht nur per Setter
Adder (ohne Null Prüfung!)
Getter (ohne Null Prüfung...
VERSCHACHTELTE MAPPINGS
@Mapping(source = "source.nested.param" target = "param")
public Target toTarget(Source source);
i...
MAPPING VON ENUM-TYPEN
@Mapping(source = "FINAL", target = "LAST")
TargetEnum map(SourceEnum enum);
String-Match oder expl...
MAPPING DEFAULTS UND KONSTANTEN
@Mapping(source = "src", target = "dest", defaultValue = "-1")
Default-Werte als Ersatz be...
QUALIFIER
Unterscheidung bei identischem Quell- und Zieltyp
Ohne Qualifier Zuordnung nicht eindeutig = Compiler Fehler
spe...
BEAN-FACTORIES
Als Ersatz für Standard-Konstruktor
Selbst geschriebene Factory-Methoden (leere Parameterliste,
Rückgabetyp...
MAPPING PER EXPRESSION
@Mapping(
expression = "java(java.util.UUID.randomUUID().toString())",
target = "uniqueId")
TargetD...
UNTERSCHIEDLICHE QUELLEN
@Mappings({
@Mapping(source = "param1.src", target = "dest1"),
@Mapping(source = "param2.src", ta...
MAPPING ALS UPDATE
@Mapper
public interface Mapper {
Target update(Source src, @MappingTarget Target target);
}
mehrere Qu...
BIDIREKTIONALES MAPPING
@Mapper
public interface Mapper {
@Mapping(source = "special", target = "destParam")
Dto map(Entit...
CUSTOM MAPPER #1
@Mapper(uses = CustomMapper.class)
public interface Mapper {
...
}
public class CustomMapper {
public Tar...
CUSTOM MAPPER #2
@Mapper(uses = CustomMapper.class)
public interface Mapper {
...
}
@Mapper
public abstract class CustomMa...
KOMPONENTENMODELLE
Konfiguration pro Mapper
Mehrere werden bereits unterstützt
Spring (@Component, @Autowired)
CDI (@Appli...
KONFIGURATION
@MapperConfig(componentModel = ..., uses = ..., ...)
public interface DefaultMapperConfig {
...
}
@Mapper(co...
MAPPING ASPEKTE #1
Decorator
angepasster Code für ausgewählte Methoden
Aber: greift nur, wenn Methode vom eigenen Code ode...
MAPPING ASPEKTE #2
@BeforeMappingund @AfterMapping
Matching auf Mapping-Methoden anhand Quell- und Zieltypen
@Mapper
publi...
EXCEPTIONHANDLING
Checked Exceptions
nur wenn an Mapping Methode deklariert
ansonsten gewrapped in RuntimeException
Runtim...
FAZIT & AUSBLICK
MapStruct ist ready-to-use
umfangreiche Dokumentation
lebendige Community
keine Bugs, die den Einsatz ver...
VIELEN DANK FÜR EURE AUFMERKSAMKEIT!
MapStruct - der neue Stern am Bean-Mapping Himmel?!
Prochain SlideShare
Chargement dans…5
×

MapStruct - der neue Stern am Bean-Mapping Himmel?!

1 078 vues

Publié le

Speaker: Gerrit Brehmer
Event: W-JAX 2015
07.11.2015
weitere Vorträge von inovex: https://www.inovex.de/de/content-pool/vortraege

Bean Mapping ist kein Thema, mit dem man sich lange aufhalten möchte. Jedoch wird es häufig zum Mappen von internen Klassenstrukturen zu DTOs und wieder zurück benötigt. Wird der Mapping-Code selbst geschrieben, sind Flüchtigkeitsfehler an der Tagesordnung. Alternativen wie Dozer oder BeanUtils nehmen einiges an Arbeit ab, sitzen aber mit Reflection und XML-Konfiguration wie ein Fremdkörper in der Applikation und können die Performance beeinträchtigen.

MapStruct verspricht dagegen Typsicherheit, Schnelligkeit und Flexibilität. Der Vortrag zeigt die Stärken der Java-Only-Lösung, die (fast) den kompletten ungeliebten Boilerplate-Mapping-Code anhand von annotierten Interfaces zur Compile-Zeit generiert. Die übrig gebliebenen Sonderfälle übernimmt man dann gerne selbst.

Publié dans : Logiciels
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

MapStruct - der neue Stern am Bean-Mapping Himmel?!

  1. 1. WER ERZÄHLT DIE NÄCHSTEN 55+ MINUTEN ETWAS? Gerrit Brehmer, Karlsruhe Auf der Arbeit: Software-Entwickler/Architekt ( / Projektleiter) bei der inovex GmbH In der Freizeit: Smart Home
  2. 2. BEAN-MAPPING: EINSATZ Wann müssen Beans gemappt werden? Entities zu DTOs interne zu generierten Klassen (JAXB etc.) zur Einbindung externer Dienste standardisierten Schnittstellen eigenen REST/SOAP Schnittstellen Allgemein Austauschformate zwischen Schichten und Applikationen
  3. 3. BEAN MAPPING: UMSETZUNG Was benutzen wir dafür bisher? von Hand geschriebener Mapping-Code typsicher, schnell fehleranfällig, aufwendig Dozer wenig Aufwand, Rekursives Auto-Mapping Reflection & XML: langsam Apache Commons BeanUtils wenig Aufwand Reflection, nur nicht komplexe Properties, langsam
  4. 4. GEHT ES BESSER? Wunschliste schnell typsicher wenig Aufwand automatisches Mapping Null-Prüfungen Konvertierungen von "ähnlichen" Typen Fehlendes Mapping schnell erkennen nachvollziehbar
  5. 5. MAPSTRUCT mapstruct.org / github.com/mapstruct OpenSource (Lizenz: Apache 2.0) Initator & Maintainer: Gunnar Morling (RedHat, Hibernate Team) Aktuelle Version: 1.0.0.CR2 (Final Release in Kürze) Weiterentwicklung/Support mehrere Stamm-Entwickler schnelles Feedback kontinuierliche Weiterentwicklung
  6. 6. WIE FUNKTIONIERT MAPSTRUCT Annotation Processor Verarbeitet Annotations am eigenen Quellcode siehe andere bekannte Libs: JPA MetaModel, Lombok, QueryDSL z.B. mit Hilfe maven-processor-plugin Generiert Java Quellcode Zusammenspiel verschiedener FreeMarker Templates
  7. 7. DEMO
  8. 8. INTEGRATION IN ECLIPSE #1 MapStruct eclipse Plugin noch work-in-progress Hauptsächlich noch fehlende Features, keine Bugs Code Completion: JAXB Listen, Nested Properties Quick Fix: Collection Mappings
  9. 9. INTEGRATION IN ECLIPSE #2 m2e APT Plugin Aktivierung nicht vergessen! Inkompatibilitäten mit Eclipse Compiler pre Mars (ab 1.0.0.CR2) Manchmal 'Clean Project' notwendig Maven: build-helper- maven-plugin automatische Build-Path Anpassung
  10. 10. GENERIERTE ABHÄNGIGKEITEN Zu mappende Klassen sind ebenfalls generiert (z.B. JAXB per Schema) Resultat: Compiler Fehler bei Generierung MapStruct Mapper Lösung: Weiteres Maven Modul/Artefakt für abhängige Klassen Maven Plugins in unterschiedliche Phasen verlegen
  11. 11. AUTOMAPPING #1 Primitive & Wrapper-Typen Datums-Typen Joda / Java 8 DateTime API Klassen Date Calendar dest.setLocalDateTime(java.time.LocalDateTime.ofInstant( src.getDate().toInstant(), java.time.ZoneId.systemDefault()) );
  12. 12. AUTOMAPPING #2 Collection- & Array-Typen Mapping nicht nur per Setter Adder (ohne Null Prüfung!) Getter (ohne Null Prüfung!) Setter Mapping-Methoden zwischen Collection/Array Typen müssen nicht definiert werden Maps JAXB JAXBElement XMLGregorianCalendar
  13. 13. VERSCHACHTELTE MAPPINGS @Mapping(source = "source.nested.param" target = "param") public Target toTarget(Source source); inkl. Null-Prüfungen Bisher nur für Quell-Parameter Feature Request für Ziel-Parameter vorhanden
  14. 14. MAPPING VON ENUM-TYPEN @Mapping(source = "FINAL", target = "LAST") TargetEnum map(SourceEnum enum); String-Match oder explizites Mapping fehlende Mappings zu Zielwerten werden signalisiert
  15. 15. MAPPING DEFAULTS UND KONSTANTEN @Mapping(source = "src", target = "dest", defaultValue = "-1") Default-Werte als Ersatz bei null-Werten in Quell- Instanzen @Mapping(constant = "CONST", target = "dest") String-Konstanten, auf die bei Bedarf Standard- Converter oder andere Mapping Methoden angewendet werden
  16. 16. QUALIFIER Unterscheidung bei identischem Quell- und Zieltyp Ohne Qualifier Zuordnung nicht eindeutig = Compiler Fehler spezielle Mappings für ansonsten automatisch generierten Mapping- Code @Qualifier @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Marker { } @Marker public String specialStringMapping(String source) { ... } @Mapping(source = "src", target = "dest", qualifiedBy = Marker.class) public Target map(Source source);
  17. 17. BEAN-FACTORIES Als Ersatz für Standard-Konstruktor Selbst geschriebene Factory-Methoden (leere Parameterliste, Rückgabetyp = Zieltyp) Generische Factories möglich Verwendung bereits vorhandener (z.B. ObjectFactory von JAXB) @Mapper(uses = CustomFactory.class) public interface Mapper { ... } public class CustomFactory { public TargetDto createTargetDto() { .... } public <T extends AbstractEntity> T createEntity(@TargetType Class<T> entityClass) { ... } }
  18. 18. MAPPING PER EXPRESSION @Mapping( expression = "java(java.util.UUID.randomUUID().toString())", target = "uniqueId") TargetDto mapTo(SourceEntity source); Aktuell nur Unterstützung für Java Code echte Skriptsprachen für zukünftige Versionen geplant Notwendige Imports können am @Mapper konfiguriert werden
  19. 19. UNTERSCHIEDLICHE QUELLEN @Mappings({ @Mapping(source = "param1.src", target = "dest1"), @Mapping(source = "param2.src", target = "dest2") }) Target map(SourceOne param1, SourceTwo param2); Aber: Sind nur im Custom-Code / Expressions wiedervendbar
  20. 20. MAPPING ALS UPDATE @Mapper public interface Mapper { Target update(Source src, @MappingTarget Target target); } mehrere Quellen möglich Return Type: voidoder identisch mit Ziel-Typ
  21. 21. BIDIREKTIONALES MAPPING @Mapper public interface Mapper { @Mapping(source = "special", target = "destParam") Dto map(Entity source); @InheritInverseConfiguration Entity map(Dto source); } Ausnahmen geschachtelte Quell-Property Konstanten Expressions
  22. 22. CUSTOM MAPPER #1 @Mapper(uses = CustomMapper.class) public interface Mapper { ... } public class CustomMapper { public TargetDto toTarget(Source source) { .... } } Mapper Klassen notwendig, wenn automatische Mapping-Methoden nicht generiert werden können Einzelnes Element gemappt auf Liste Liste mit Inhalten aus verschiedenen Quellen Liste komplexer Elemente gemappt auf Liste primitiver Werte
  23. 23. CUSTOM MAPPER #2 @Mapper(uses = CustomMapper.class) public interface Mapper { ... } @Mapper public abstract class CustomMapper { public TargetDto toTarget(Source source) { .... } @Mappings(...) public abstract NestingTargetDto toNestingTarget(NestingSource source); } Abstrakte Klassen Ähnlich wie Mapper per Interface abstrakte Methoden werden generiert public Methoden enthalten den nicht generierbaren Mapper-Code
  24. 24. KOMPONENTENMODELLE Konfiguration pro Mapper Mehrere werden bereits unterstützt Spring (@Component, @Autowired) CDI (@ApplicationScoped, @Inject) JSR 330 (@Named, @Inject) Alle miteinander verbundenen Mapper müssen dasselbe Komponentenmodell verwenden Keine Abhängigkeit zu MapStruct zur Laufzeit @Mapper(componentModel = "spring") public interface Mapper { ... } @Component public class MapperImpl { ... }
  25. 25. KONFIGURATION @MapperConfig(componentModel = ..., uses = ..., ...) public interface DefaultMapperConfig { ... } @Mapper(config = "DefaultMapperConfig") public interface Mapper { ... }
  26. 26. MAPPING ASPEKTE #1 Decorator angepasster Code für ausgewählte Methoden Aber: greift nur, wenn Methode vom eigenen Code oder anderen Mapper-Klassen aufgerufen wird @Mapper @DecoratedWith(MapperDecorator.class) public interface Mapper { ... } public abstract class MapperDecorator implements Mapper { private final Mapper delegate; public MapperDecorator(Mapper delegate) { this.delegate = delegate; } @Override public Target toTarget(Source source) { Target target = delegate.toTarget(source); // ... custom mapping ... }
  27. 27. MAPPING ASPEKTE #2 @BeforeMappingund @AfterMapping Matching auf Mapping-Methoden anhand Quell- und Zieltypen @Mapper public abstract class Mapper { @BeforeMapping void flushEntity(AbstractEntity entity) { // flush entity to init all fields } @AfterMapping void manuelUpdateMissing(Source src, @MappingTarget Target target) { // e.g. as alternative for expressions / custom mapper } }
  28. 28. EXCEPTIONHANDLING Checked Exceptions nur wenn an Mapping Methode deklariert ansonsten gewrapped in RuntimeException RuntimeExceptions ohne Anpassung
  29. 29. FAZIT & AUSBLICK MapStruct ist ready-to-use umfangreiche Dokumentation lebendige Community keine Bugs, die den Einsatz verhndern Große Funktionsauswahl: Viele Wege führen zum Ziel! So viel wie möglich automatisch mappen Damit verbundene Checks durch MapStruct minimieren Mapping Fehler Das Feature-Set ist noch nicht komplett: Weitere nützliche Features werden sicher folgen!
  30. 30. VIELEN DANK FÜR EURE AUFMERKSAMKEIT!

×