0
# Standalone Builders
1
2
AutoBuilder generates builders for existing classes or constructors, allowing you to add fluent APIs to classes that weren't originally designed with builders.
3
4
## Basic Standalone Builder
5
6
```java { .api }
7
// Existing class that you want to build
8
public class Person {
9
private final String name;
10
private final int age;
11
private final String email;
12
13
public Person(String name, int age, String email) {
14
this.name = name;
15
this.age = age;
16
this.email = email;
17
}
18
19
// getters...
20
}
21
22
// Generate a builder for the existing class
23
@AutoBuilder(ofClass = Person.class)
24
public abstract class PersonBuilder {
25
public static PersonBuilder builder() {
26
return new AutoBuilder_PersonBuilder();
27
}
28
29
public abstract PersonBuilder setName(String name);
30
public abstract PersonBuilder setAge(int age);
31
public abstract PersonBuilder setEmail(String email);
32
public abstract Person build();
33
}
34
```
35
36
## Usage Example
37
38
```java
39
Person person = PersonBuilder.builder()
40
.setName("Alice")
41
.setAge(30)
42
.setEmail("alice@example.com")
43
.build();
44
```
45
46
## Builder for Static Factory Method
47
48
Build objects via static factory methods instead of constructors:
49
50
```java { .api }
51
// Existing class with static factory
52
public class DatabaseConnection {
53
private final String host;
54
private final int port;
55
private final String database;
56
57
private DatabaseConnection(String host, int port, String database) {
58
this.host = host;
59
this.port = port;
60
this.database = database;
61
}
62
63
public static DatabaseConnection connect(String host, int port, String database) {
64
return new DatabaseConnection(host, port, database);
65
}
66
}
67
68
// Builder targeting the static method
69
@AutoBuilder(ofClass = DatabaseConnection.class, callMethod = "connect")
70
public abstract class DatabaseConnectionBuilder {
71
public static DatabaseConnectionBuilder builder() {
72
return new AutoBuilder_DatabaseConnectionBuilder();
73
}
74
75
public abstract DatabaseConnectionBuilder setHost(String host);
76
public abstract DatabaseConnectionBuilder setPort(int port);
77
public abstract DatabaseConnectionBuilder setDatabase(String database);
78
public abstract DatabaseConnection build();
79
}
80
```
81
82
Usage:
83
84
```java
85
DatabaseConnection conn = DatabaseConnectionBuilder.builder()
86
.setHost("localhost")
87
.setPort(5432)
88
.setDatabase("myapp")
89
.build();
90
```
91
92
## Builder with Default Values
93
94
Set default values in the builder factory:
95
96
```java { .api }
97
@AutoBuilder(ofClass = HttpConfig.class)
98
public abstract class HttpConfigBuilder {
99
public static HttpConfigBuilder builder() {
100
return new AutoBuilder_HttpConfigBuilder()
101
.setTimeout(5000)
102
.setRetries(3)
103
.setFollowRedirects(true);
104
}
105
106
public abstract HttpConfigBuilder setUrl(String url);
107
public abstract HttpConfigBuilder setTimeout(int timeout);
108
public abstract HttpConfigBuilder setRetries(int retries);
109
public abstract HttpConfigBuilder setFollowRedirects(boolean followRedirects);
110
public abstract HttpConfig build();
111
}
112
```
113
114
## Builder for Generic Classes
115
116
AutoBuilder supports generic types:
117
118
```java { .api }
119
// Generic class to build
120
public class Pair<T, U> {
121
private final T first;
122
private final U second;
123
124
public Pair(T first, U second) {
125
this.first = first;
126
this.second = second;
127
}
128
129
// getters...
130
}
131
132
// Generic builder
133
@AutoBuilder(ofClass = Pair.class)
134
public abstract class PairBuilder<T, U> {
135
public static <T, U> PairBuilder<T, U> builder() {
136
return new AutoBuilder_PairBuilder<>();
137
}
138
139
public abstract PairBuilder<T, U> setFirst(T first);
140
public abstract PairBuilder<T, U> setSecond(U second);
141
public abstract Pair<T, U> build();
142
}
143
```
144
145
Usage:
146
147
```java
148
Pair<String, Integer> pair = PairBuilder.<String, Integer>builder()
149
.setFirst("hello")
150
.setSecond(42)
151
.build();
152
```
153
154
## Builder for Classes with Multiple Constructors
155
156
AutoBuilder will match the constructor based on parameter names and types:
157
158
```java { .api }
159
// Class with multiple constructors
160
public class Employee {
161
private final String name;
162
private final String department;
163
private final int salary;
164
private final String email;
165
166
// Constructor 1
167
public Employee(String name, String department) {
168
this(name, department, 0, null);
169
}
170
171
// Constructor 2
172
public Employee(String name, String department, int salary, String email) {
173
this.name = name;
174
this.department = department;
175
this.salary = salary;
176
this.email = email;
177
}
178
}
179
180
// Builder matches the 4-parameter constructor
181
@AutoBuilder(ofClass = Employee.class)
182
public abstract class EmployeeBuilder {
183
public static EmployeeBuilder builder() {
184
return new AutoBuilder_EmployeeBuilder();
185
}
186
187
public abstract EmployeeBuilder setName(String name);
188
public abstract EmployeeBuilder setDepartment(String department);
189
public abstract EmployeeBuilder setSalary(int salary);
190
public abstract EmployeeBuilder setEmail(String email);
191
public abstract Employee build();
192
}
193
```
194
195
## Builder for Record Classes (Java 14+)
196
197
AutoBuilder can generate builders for record classes:
198
199
```java { .api }
200
// Record class
201
public record Point(double x, double y, String label) {}
202
203
// Builder for the record
204
@AutoBuilder(ofClass = Point.class)
205
public abstract class PointBuilder {
206
public static PointBuilder builder() {
207
return new AutoBuilder_PointBuilder();
208
}
209
210
public abstract PointBuilder setX(double x);
211
public abstract PointBuilder setY(double y);
212
public abstract PointBuilder setLabel(String label);
213
public abstract Point build();
214
}
215
```
216
217
Usage:
218
219
```java
220
Point origin = PointBuilder.builder()
221
.setX(0.0)
222
.setY(0.0)
223
.setLabel("Origin")
224
.build();
225
```
226
227
## Builder with Validation
228
229
Add validation to standalone builders:
230
231
```java { .api }
232
@AutoBuilder(ofClass = Account.class)
233
public abstract class AccountBuilder {
234
public static AccountBuilder builder() {
235
return new AutoBuilder_AccountBuilder();
236
}
237
238
public abstract AccountBuilder setUsername(String username);
239
public abstract AccountBuilder setEmail(String email);
240
public abstract AccountBuilder setAge(int age);
241
242
abstract Account autoBuild(); // Package-private
243
244
public Account build() {
245
Account account = autoBuild();
246
validate(account);
247
return account;
248
}
249
250
private void validate(Account account) {
251
if (account.getUsername().length() < 3) {
252
throw new IllegalArgumentException("Username must be at least 3 characters");
253
}
254
if (!account.getEmail().contains("@")) {
255
throw new IllegalArgumentException("Invalid email format");
256
}
257
if (account.getAge() < 0) {
258
throw new IllegalArgumentException("Age must be non-negative");
259
}
260
}
261
}
262
```
263
264
## Builder for Immutable Collections
265
266
Use AutoBuilder with collection factory methods:
267
268
```java { .api }
269
// Building ImmutableList
270
@AutoBuilder(ofClass = ImmutableList.class, callMethod = "of")
271
public abstract class ImmutableListBuilder<T> {
272
public static <T> ImmutableListBuilder<T> builder() {
273
return new AutoBuilder_ImmutableListBuilder<>();
274
}
275
276
// For ImmutableList.of(T... elements)
277
public abstract ImmutableListBuilder<T> setElements(T... elements);
278
public abstract ImmutableList<T> build();
279
}
280
```
281
282
Usage:
283
284
```java
285
ImmutableList<String> list = ImmutableListBuilder.<String>builder()
286
.setElements("a", "b", "c")
287
.build();
288
```
289
290
## Builder for Annotation Creation
291
292
Combine with @AutoAnnotation for fluent annotation building:
293
294
```java { .api }
295
// Annotation to build
296
public @interface ApiEndpoint {
297
String path();
298
String method() default "GET";
299
boolean authenticated() default true;
300
}
301
302
// AutoAnnotation factory
303
public class Annotations {
304
@AutoAnnotation
305
public static ApiEndpoint apiEndpoint(String path, String method, boolean authenticated) {
306
return new AutoAnnotation_Annotations_apiEndpoint(path, method, authenticated);
307
}
308
}
309
310
// Builder for the annotation
311
@AutoBuilder(callMethod = "apiEndpoint", ofClass = Annotations.class)
312
public abstract class ApiEndpointBuilder {
313
public static ApiEndpointBuilder builder() {
314
return new AutoBuilder_ApiEndpointBuilder()
315
.setMethod("GET")
316
.setAuthenticated(true);
317
}
318
319
public abstract ApiEndpointBuilder setPath(String path);
320
public abstract ApiEndpointBuilder setMethod(String method);
321
public abstract ApiEndpointBuilder setAuthenticated(boolean authenticated);
322
public abstract ApiEndpoint build();
323
}
324
```
325
326
Usage:
327
328
```java
329
ApiEndpoint endpoint = ApiEndpointBuilder.builder()
330
.setPath("/api/users")
331
.setMethod("POST")
332
.build();
333
```
334
335
## Nested Class Builders
336
337
AutoBuilder works with nested classes:
338
339
```java { .api }
340
public class OuterClass {
341
public static class InnerClass {
342
private final String value;
343
344
public InnerClass(String value) {
345
this.value = value;
346
}
347
}
348
}
349
350
@AutoBuilder(ofClass = OuterClass.InnerClass.class)
351
public abstract class InnerClassBuilder {
352
public static InnerClassBuilder builder() {
353
return new AutoBuilder_InnerClassBuilder();
354
}
355
356
public abstract InnerClassBuilder setValue(String value);
357
public abstract OuterClass.InnerClass build();
358
}
359
```
360
361
## Error Handling
362
363
AutoBuilder provides clear error messages for common issues:
364
365
```java
366
// Compilation error if parameter names don't match constructor
367
@AutoBuilder(ofClass = Person.class)
368
public abstract class BadPersonBuilder {
369
public abstract BadPersonBuilder setFullName(String fullName); // ERROR: no parameter named 'fullName'
370
public abstract Person build();
371
}
372
373
// Runtime validation in build methods
374
Account account = AccountBuilder.builder()
375
.setUsername("ab") // Will throw IllegalArgumentException during build()
376
.build();
377
```