Lombok Builder met standaardwaarde

1. Inleiding

In deze korte tutorial zullen we onderzoeken hoe we standaardwaarden voor attributen kunnen opgeven wanneer we het builderpatroon gebruiken met Lombok.

Bekijk ook zeker onze intro voor Lombok.

2. Afhankelijkheden

We zullen Lombok gebruiken in deze tutorial, en daarvoor hebben we maar één afhankelijkheid nodig:

 org.projectlombok lombok 1.18.10 voorzien 

3. POJO met Lombok Builder

Laten we eerst eens kijken hoe Lombok ons ​​kan helpen met het verwijderen van de boilerplate-code die nodig is om het builder-patroon te implementeren.

We beginnen met een eenvoudige POJO:

openbare klasse Pojo {private String-naam; privé booleaans origineel; }

Om deze klasse nuttig te laten zijn, hebben we getters nodig. Als we deze klasse bijvoorbeeld met een ORM willen gebruiken, hebben we waarschijnlijk een standaardconstructor nodig.

Bovendien willen we een bouwer voor deze klas. Met Lombok kunnen we dit allemaal hebben met enkele eenvoudige annotaties:

@Getter @Builder @NoArgsConstructor @AllArgsConstructor openbare klasse Pojo {private String-naam; privé booleaans origineel; }

4. Verwachtingen formuleren

Laten we enkele verwachtingen definiëren voor wat we willen bereiken in de vorm van unit-tests.

De eerste en basisvereiste is de aanwezigheid van standaardwaarden nadat we een object hebben gebouwd met een builder:

@Test openbare leegte gegevenBuilderWithDefaultValue_ThanDefaultValueIsPresent () {Pojo build = Pojo.builder () .build (); Assert.assertEquals ("foo", build.getName ()); Assert.assertTrue (build.isOriginal ()); }

Natuurlijk mislukt deze test sinds de @Bouwer annotatie vult geen waarden. We lossen dit binnenkort op.

Als we een ORM gebruiken, is deze meestal afhankelijk van een standaardconstructor. We zouden dus hetzelfde gedrag moeten verwachten van de standaardconstructor als van de builder:

@Test openbare leegte gegevenBuilderWithDefaultValue_NoArgsWorksAlso () {Pojo build = Pojo.builder () .build (); Pojo pojo = nieuwe Pojo (); Assert.assertEquals (build.getName (), pojo.getName ()); Assert.assertTrue (build.isOriginal () == pojo.isOriginal ()); }

In dit stadium slaagt deze test.

Laten we nu eens kijken hoe we beide tests kunnen laten slagen!

5. Lombok's Bouwer. Standaard Annotatie

Sinds Lombok v1.16.16 kunnen we @Bouwer'S innerlijke annotatie:

// class annotaties zoals voorheen public class Pojo {@ Builder.Default private String name = "foo"; @ Builder.Default private boolean original = true; }

Het is eenvoudig en leesbaar, maar het heeft enkele gebreken.

Hiermee zullen de standaardwaarden aanwezig zijn bij de builder, waardoor de eerste testcase slaagt. Helaas krijgt de constructor no-args niet de standaardwaarden, waardoor de tweede testcase mislukt. Zelfs als de constructor no-args niet wordt gegenereerd maar expliciet is geschreven.

Deze bijwerking van de Bouwer. Standaard annotatie is vanaf het begin aanwezig en zal waarschijnlijk nog lang bij ons blijven.

6. Initialiseer de Builder

We kunnen proberen om beide tests te laten slagen door standaardwaarden te definiëren in een minimalistische builderimplementatie:

// class annotaties zoals voorheen public class Pojo {private String name = "foo"; privé booleaans origineel = waar; openbare statische klasse PojoBuilder {private String name = "foo"; privé booleaans origineel = waar; }}

Op deze manier zullen beide tests slagen.

Helaas is de prijs codeduplicatie. Voor een POJO met tientallen velden kan het foutgevoelig zijn om de dubbele initialisatie te behouden.

Maar als we bereid zijn deze prijs te betalen, moeten we nog voor één ding zorgen. Als we onze klasse hernoemen met een refactoring binnen onze IDE, wordt de statische innerlijke klasse niet automatisch hernoemd. Dan zal Lombok het niet vinden en zal onze code breken.

Om dit risico te elimineren, kunnen we de annotatie van de bouwer versieren:

// class annotaties zoals voorheen @Builder (builderClassName = "PojoBuilder") public class Pojo {private String name = "foo"; privé booleaans origineel = waar; openbare statische klasse PojoBuilder {private String name = "foo"; privé booleaans origineel = waar; }}

7. Met behulp van toBuilder

@Bouwer ondersteunt ook het genereren van een instantie van de builder vanuit een instantie van de originele klasse. Deze functie is standaard niet ingeschakeld. We kunnen het inschakelen door de toBuilder parameter in de annotatie van de bouwer:

// class annotaties zoals voorheen @Builder (toBuilder = true) public class Pojo {private String name = "foo"; privé booleaans origineel = waar; }

Hiermee, we kunnen de dubbele initialisatie verwijderen.

Daar is natuurlijk een prijs voor. We moeten de klasse instantiëren om een ​​bouwer te maken. We moeten onze tests dus ook aanpassen:

@Test openbare leegte gegevenBuilderWithDefaultValue_ThenDefaultValueIsPresent () {Pojo build = nieuwe Pojo (). ToBuilder () .build (); Assert.assertEquals ("foo", build.getName ()); Assert.assertTrue (build.isOriginal ()); } @Test openbare leegte gegevenBuilderWithDefaultValue_thenNoArgsWorksAlso () {Pojo build = nieuwe Pojo (). ToBuilder () .build (); Pojo pojo = nieuwe Pojo (); Assert.assertEquals (build.getName (), pojo.getName ()); Assert.assertTrue (build.isOriginal () == pojo.isOriginal ()); }

Nogmaals, beide tests slagen, dus we hebben dezelfde standaardwaarde als we de constructor no-args gebruiken als wanneer we de builder gebruiken.

8. Conclusie

We hebben dus verschillende opties bekeken om standaardwaarden voor de Lombok-builder te geven.

De bijwerking van de Bouwer.Standaard annotatie is het waard om in de gaten te houden. Maar de andere opties hebben ook hun nadelen. We moeten dus zorgvuldig kiezen op basis van de huidige situatie.

Zoals altijd is de code beschikbaar op GitHub.