Het pleidooi voor BeanMapper

In Java-applicaties worden conform best practices aparte klassen gebruikt voor invoer en uitvoer. BeanMapper ondersteunt dat design pattern door de overheveling van data te vereenvoudigen.

Het pleidooi voor BeanMapper
Het overhevelen van data van de ene emmer naar de ander, saai maar noodzakelijk

Wij hebben een library geschreven waarmee in een Java-applicatie gelijksoortige data automatisch van de ene klasse naar een andere klasse wordt gekopieerd. Deze library heet BeanMapper. Dit artikel is geschreven om de bestaansreden van BeanMapper toe te lichten.

De entiteit zelf voor invoer en uitvoer

In een Java-applicatie waar gebruik wordt gemaakt van JPA / Hibernate voor het opslaan van entiteiten, kun je in theorie de entiteit zelf gebruiken om invoer vanuit de browser en uitvoer naar de browser te regelen. Dat ziet er dan als volgt uit:

De naïeve aanpak: het hergebruiken van de Entity voor invoer en uitvoer

Dit patroon introduceert echter wel een aantal problemen:

  1. vuile invoer; het wordt voor partijen mogelijk om velden in de entiteit aan te passen, ook als deze niet aangepast zouden mogen worden. Je kunt hierbij denken aan verwijzingen naar andere records, wachtwoorden of rechten in een systeem.
  2. vuile uitvoer; alle velden van een entiteit worden in principe meegegeven aan de buitenwereld, ook velden die je in principe niet wil ontsluiten. Zelfs als de gebruiker de velden niet direct ziet, worden ze wel meegegeven en zijn ze vanuit een moderne browser eenvoudig in te zien, met bijvoorbeeld DevTools.

Scrubben van invoer en uitvoer?

Je kunt ervoor kiezen om met maatwerk-code de invoer in de gaten te houden en bijvoorbeeld specifieke velden uit de invoer te scrubben alvorens de data te accepteren. Eenzelfde oplossing staat tot je beschikking bij het genereren van de uitvoer.

Maar het scrubben van in- en uitvoervelden is niet zonder risico's, een aantal technisch van aard, maar zeker niet in de laatste plaats dat je je continu bewust moet zijn welke velden wel en welke niet opgeschoond moeten worden. Vergeet er één en de deur staat weer wagenwijd open.

Best practice: aparte klassen voor in- en uitvoer

Het is gebruikelijk om aparte Java klassen te maken voor in- en uitvoer. De invoer klassen worden gekoppeld aan formulier-logica en de uitvoer-klassen aan bijvoorbeeld data voor tabellen of lijsten in schermen. Deze klassen zijn doorgaans volwaardige subsets van de entiteit. Dat ziet er dan als volgt uit:

Verbetering: de introductie van aparte invoer (Form) en uitvoer (Result) klassen

Alleen als je dat doet, ga je logica moeten introduceren die de kopieerslag uitvoert. Je schrijft dan regels die de data uit de bron haalt en plaatst in het doel, zoals dit:

// Mapping from Form to Entity
Car car = new Car();
car.setOverrideCode(form.overrideCode);
car.setLicensePlate(form.licensePlate);

// Mapping from Entity to Result
CarResult carResult = new CarResult();
carResult.id = car.getId();
carResult.licensePlate = car.getLicensePlate();
carResult.owner = car.getOwner();

Automatiseren van de overzetting

Het feit dat de in- en uitvoer objecten volledige subsets zijn van de entiteit, maakt dat het mogelijk is om te automatiseren. Je kunt een tool opdracht geven om voor alle overeenkomstige velden de inhoud van de bron naar het doel te kopiëren. Dat ziet er dan als volgt uit:

Optimalisatie: automatisch kopiëren van invoer naar Entity en van Entity naar uitvoer

In code is het dan een betrekkelijk eenvoudige handeling geworden:

BeanMapper beanMapper = new BeanMapper();

// Mapping from Form to Entity
Car car = beanMapper.map(form, Car.class);

// Mapping from Entity to Result
CarResult carResult = beanMapper.map(car, CarResult.class);

Daarom dus BeanMapper

Velden die niet bestaan, worden niet meegenomen. In plaats van dat je én de Form/Result klassen én de logica om de data over te zetten, hoef je enkel de eerste groep te onderhouden. Het is een solide patroon met solide tooling waarmee je veilig software voor je klanten kunt bouwen.

Voor wie interesse heeft, BeanMapper is beschikbaar als open source library. Wij gebruiken zelf Open Source en geven daarom graag wat terug aan de community.