or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builder.mdconstructors.mddata-classes.mdexperimental.mdindex.mdlogging.mdproperty-access.mdutilities.md

builder.mddocs/

0

# Builder Pattern

1

2

Fluent builder pattern implementation with support for inheritance, default values, collection handling, and Jackson integration. The builder pattern provides a clean, readable way to construct objects with many optional parameters.

3

4

## Capabilities

5

6

### @Builder Annotation

7

8

Generates a comprehensive builder pattern implementation with fluent method chaining and customizable naming conventions.

9

10

```java { .api }

11

/**

12

* Creates a builder pattern implementation for the annotated class, constructor, or method.

13

* Generates an inner builder class with fluent setter methods and a build() method.

14

*/

15

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})

16

@interface Builder {

17

/**

18

* Name of the static method that creates a new builder instance

19

* @return Method name (default: "builder"). Empty string suppresses generation

20

*/

21

String builderMethodName() default "builder";

22

23

/**

24

* Name of the method in the builder class that creates the final instance

25

* @return Method name for building the instance (default: "build")

26

*/

27

String buildMethodName() default "build";

28

29

/**

30

* Name of the generated builder class

31

* @return Builder class name. Defaults to (TypeName)Builder or (ReturnTypeName)Builder

32

*/

33

String builderClassName() default "";

34

35

/**

36

* Generate a toBuilder() instance method that creates a pre-populated builder

37

* @return Whether to generate toBuilder() method (default: false)

38

*/

39

boolean toBuilder() default false;

40

41

/**

42

* Access level for the generated builder class

43

* @return Access level for the builder class (default: PUBLIC)

44

*/

45

AccessLevel access() default AccessLevel.PUBLIC;

46

47

/**

48

* Prefix for builder setter methods

49

* @return Prefix to prepend to setter method names (default: empty)

50

*/

51

String setterPrefix() default "";

52

}

53

54

/**

55

* Marks a field for default value in builder pattern

56

* Field must have an initializing expression

57

*/

58

@Target(ElementType.FIELD)

59

@interface Builder.Default {}

60

61

/**

62

* Specifies how to obtain field value for toBuilder functionality

63

*/

64

@Target({ElementType.FIELD, ElementType.PARAMETER})

65

@interface Builder.ObtainVia {

66

/**

67

* Field name to use for obtaining value

68

* @return Field name for this.fieldName access

69

*/

70

String field() default "";

71

72

/**

73

* Method name to use for obtaining value

74

* @return Method name for this.methodName() access

75

*/

76

String method() default "";

77

78

/**

79

* Whether the method is static

80

* @return True for ClassName.method(this) access pattern

81

*/

82

boolean isStatic() default false;

83

}

84

```

85

86

**Usage Examples:**

87

88

```java

89

import lombok.Builder;

90

import lombok.Getter;

91

import lombok.ToString;

92

93

@Builder

94

@Getter

95

@ToString

96

public class Person {

97

private String firstName;

98

private String lastName;

99

private int age;

100

private String email;

101

private String phone;

102

}

103

104

// Generated builder class and usage:

105

Person person = Person.builder()

106

.firstName("John")

107

.lastName("Doe")

108

.age(30)

109

.email("john.doe@example.com")

110

.phone("555-1234")

111

.build();

112

```

113

114

Builder with default values:

115

```java

116

@Builder

117

@Getter

118

public class Configuration {

119

private String host;

120

121

@Builder.Default

122

private int port = 8080;

123

124

@Builder.Default

125

private boolean ssl = false;

126

127

@Builder.Default

128

private long timeout = 30000L;

129

}

130

131

// Usage with defaults:

132

Configuration config1 = Configuration.builder()

133

.host("localhost")

134

.build(); // Uses default port=8080, ssl=false, timeout=30000L

135

136

Configuration config2 = Configuration.builder()

137

.host("example.com")

138

.port(443)

139

.ssl(true)

140

.build();

141

```

142

143

Builder with toBuilder support:

144

```java

145

@Builder(toBuilder = true)

146

@Getter

147

public class ApiRequest {

148

private String endpoint;

149

private String method;

150

private Map<String, String> headers;

151

private String body;

152

}

153

154

// Usage with toBuilder:

155

ApiRequest baseRequest = ApiRequest.builder()

156

.endpoint("/api/v1/users")

157

.method("GET")

158

.headers(Map.of("Accept", "application/json"))

159

.build();

160

161

// Create modified version:

162

ApiRequest postRequest = baseRequest.toBuilder()

163

.method("POST")

164

.body("{\"name\": \"John\"}")

165

.build();

166

```

167

168

Custom builder configuration:

169

```java

170

@Builder(

171

builderMethodName = "newBuilder",

172

buildMethodName = "create",

173

builderClassName = "PersonFactory",

174

setterPrefix = "with",

175

access = AccessLevel.PACKAGE

176

)

177

public class CustomPerson {

178

private String name;

179

private int age;

180

}

181

182

// Usage with custom configuration:

183

CustomPerson person = CustomPerson.newBuilder()

184

.withName("Alice")

185

.withAge(25)

186

.create();

187

```

188

189

### @Singular Annotation

190

191

Used with @Builder to generate special methods for collection fields, providing both single-item and batch addition capabilities.

192

193

```java { .api }

194

/**

195

* Applied to collection fields in @Builder classes to generate singular addition methods.

196

* Creates methods for adding single items, multiple items, and clearing the collection.

197

*/

198

@Target({ElementType.FIELD, ElementType.PARAMETER})

199

@interface Singular {

200

/**

201

* Singular name for the field. If not specified, lombok attempts to determine

202

* the singular form automatically from the field name.

203

* @return Singular form of the field name

204

*/

205

String value() default "";

206

207

/**

208

* How to handle null collections in batch addition methods

209

* @return If true, null collections are treated as empty (default: false)

210

*/

211

boolean ignoreNullCollections() default false;

212

}

213

```

214

215

**Usage Examples:**

216

217

```java

218

import lombok.Builder;

219

import lombok.Singular;

220

import lombok.Getter;

221

import java.util.*;

222

223

@Builder

224

@Getter

225

public class Team {

226

private String name;

227

228

@Singular

229

private List<String> members;

230

231

@Singular("skill")

232

private Set<String> skills;

233

234

@Singular

235

private Map<String, String> properties;

236

}

237

238

// Generated methods for collections:

239

Team team = Team.builder()

240

.name("Development Team")

241

242

// Single member additions

243

.member("Alice")

244

.member("Bob")

245

246

// Batch member addition

247

.members(Arrays.asList("Charlie", "David"))

248

249

// Single skill additions

250

.skill("Java")

251

.skill("Python")

252

253

// Batch skill addition

254

.skills(Set.of("Docker", "Kubernetes"))

255

256

// Single property additions

257

.property("department", "Engineering")

258

.property("location", "Remote")

259

260

// Batch property addition

261

.properties(Map.of("budget", "100k", "duration", "6 months"))

262

263

.build();

264

265

// Clear methods are also generated:

266

Team emptyTeam = Team.builder()

267

.name("New Team")

268

.member("Alice")

269

.clearMembers() // Removes all added members

270

.member("Bob") // Team will only have Bob

271

.build();

272

```

273

274

Singular with custom collection types:

275

```java

276

@Builder

277

@Getter

278

public class Library {

279

@Singular

280

private List<Book> books;

281

282

@Singular("author")

283

private Set<String> authors;

284

285

@Singular

286

private Map<String, Category> categories;

287

288

// Guava collections support

289

@Singular

290

private ImmutableList<String> tags;

291

292

@Singular

293

private ImmutableSet<String> genres;

294

}

295

296

// Usage:

297

Library library = Library.builder()

298

.book(new Book("Clean Code"))

299

.book(new Book("Effective Java"))

300

.books(existingBooksList)

301

302

.author("Robert Martin")

303

.author("Joshua Bloch")

304

305

.category("programming", Category.TECHNICAL)

306

.categories(existingCategoriesMap)

307

308

.tag("software")

309

.tag("java")

310

.tags(Arrays.asList("programming", "tutorial"))

311

312

.build();

313

```

314

315

### Builder Method Targeting

316

317

Applying @Builder to constructors or methods instead of classes:

318

319

```java

320

public class MathUtils {

321

322

@Builder(builderMethodName = "rangeBuilder")

323

public static IntRange createRange(int start, int end, boolean inclusive) {

324

return new IntRange(start, end, inclusive);

325

}

326

327

@Builder(builderClassName = "CircleBuilder")

328

public static Circle createCircle(

329

double centerX,

330

double centerY,

331

double radius,

332

@Builder.Default String color = "black"

333

) {

334

return new Circle(centerX, centerY, radius, color);

335

}

336

}

337

338

// Usage:

339

IntRange range = MathUtils.rangeBuilder()

340

.start(1)

341

.end(100)

342

.inclusive(true)

343

.build();

344

345

Circle circle = MathUtils.CircleBuilder()

346

.centerX(0.0)

347

.centerY(0.0)

348

.radius(5.0)

349

.color("red")

350

.build();

351

```

352

353

### Jackson Integration

354

355

Using @Builder with Jackson for JSON deserialization:

356

357

```java

358

import lombok.Builder;

359

import lombok.extern.jackson.Jacksonized;

360

import com.fasterxml.jackson.annotation.JsonProperty;

361

362

@Jacksonized

363

@Builder

364

@Getter

365

public class ApiResponse {

366

@JsonProperty("status_code")

367

private int statusCode;

368

369

private String message;

370

371

@Singular

372

private List<String> errors;

373

374

@JsonProperty("response_data")

375

private Object data;

376

}

377

378

// Jackson can now deserialize JSON directly to builder:

379

// {

380

// "status_code": 200,

381

// "message": "Success",

382

// "errors": ["warning1", "warning2"],

383

// "response_data": {"id": 1, "name": "test"}

384

// }

385

```

386

387

### Advanced Builder Patterns

388

389

Complex builder with inheritance and validation:

390

391

```java

392

@Builder(toBuilder = true)

393

@Getter

394

public class ValidationRequest {

395

@NonNull

396

private String requestId;

397

398

@Builder.Default

399

private Instant timestamp = Instant.now();

400

401

@Singular

402

private Map<String, Object> parameters;

403

404

@Singular("rule")

405

private List<ValidationRule> validationRules;

406

407

@Builder.ObtainVia(method = "getProcessingOptions")

408

private ProcessingOptions options;

409

410

// Custom validation in builder

411

public static class ValidationRequestBuilder {

412

public ValidationRequest build() {

413

if (requestId == null || requestId.trim().isEmpty()) {

414

throw new IllegalArgumentException("Request ID cannot be empty");

415

}

416

417

if (validationRules == null || validationRules.isEmpty()) {

418

throw new IllegalArgumentException("At least one validation rule required");

419

}

420

421

return new ValidationRequest(requestId, timestamp, parameters, validationRules, options);

422

}

423

}

424

}

425

426

// Usage with validation:

427

ValidationRequest request = ValidationRequest.builder()

428

.requestId("REQ-001")

429

.parameter("input", "test data")

430

.parameter("format", "json")

431

.rule(new ValidationRule("required", "input"))

432

.rule(new ValidationRule("format", "json"))

433

.build(); // Throws exception if validation fails

434

```

435

436

## Type Definitions

437

438

```java { .api }

439

/**

440

* Access levels for generated builder classes

441

*/

442

public enum AccessLevel {

443

PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE, NONE

444

}

445

446

/**

447

* Placeholder for annotation arrays

448

*/

449

@interface AnyAnnotation {}

450

451

/**

452

* Jackson integration for builder pattern

453

*/

454

@Target(ElementType.TYPE)

455

@interface Jacksonized {}

456

```