or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-generation.mdbuilders.mdextensions.mdindex.mdmemoization.mdpretty-strings.mdserialization.mdstandalone-builders.mdtagged-unions.mdvalue-classes.md

standalone-builders.mddocs/

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

```