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

utilities.mddocs/

0

# Utility Annotations

1

2

Code generation for common Java patterns including null checking, exception handling, synchronization, resource cleanup, and immutable updates. These annotations reduce boilerplate code for frequent programming tasks and improve code safety.

3

4

## Capabilities

5

6

### @NonNull Annotation

7

8

Generates automatic null-checking code for parameters, fields, and local variables, throwing NullPointerException with descriptive messages.

9

10

```java { .api }

11

/**

12

* Generates null-check code for the annotated element.

13

* For parameters: adds null check at method/constructor start

14

* For fields: adds null checks in generated setters and constructors

15

* For local variables: adds null check at assignment

16

*/

17

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})

18

@interface NonNull {}

19

```

20

21

**Usage Examples:**

22

23

```java

24

import lombok.NonNull;

25

import lombok.Setter;

26

import lombok.AllArgsConstructor;

27

28

@AllArgsConstructor

29

public class User {

30

@NonNull

31

private String name;

32

33

@Setter

34

@NonNull

35

private String email;

36

37

public void updateProfile(@NonNull String newName, @NonNull String newEmail) {

38

this.name = newName;

39

this.email = newEmail;

40

}

41

42

public void processData(@NonNull List<String> data) {

43

@NonNull String firstItem = data.get(0); // Null check on assignment

44

System.out.println("Processing: " + firstItem);

45

}

46

}

47

48

// Generated constructor with null checks:

49

// public User(String name, String email) {

50

// if (name == null) {

51

// throw new NullPointerException("name is marked non-null but is null");

52

// }

53

// if (email == null) {

54

// throw new NullPointerException("email is marked non-null but is null");

55

// }

56

// this.name = name;

57

// this.email = email;

58

// }

59

60

// Usage:

61

User user = new User("John", "john@example.com"); // OK

62

User invalid = new User(null, "email"); // Throws NullPointerException

63

user.setEmail("new@example.com"); // OK

64

user.setEmail(null); // Throws NullPointerException

65

```

66

67

### @SneakyThrows Annotation

68

69

Bypasses Java's checked exception handling requirements by using bytecode manipulation to throw checked exceptions without declaring them.

70

71

```java { .api }

72

/**

73

* Allows methods to throw checked exceptions without declaring them in throws clause.

74

* Uses bytecode manipulation to circumvent Java's checked exception system.

75

*/

76

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

77

@interface SneakyThrows {

78

/**

79

* Specific exception types to allow sneaky throwing

80

* @return Array of exception types (default: all Throwable types)

81

*/

82

Class<? extends Throwable>[] value() default Throwable.class;

83

}

84

```

85

86

**Usage Examples:**

87

88

```java

89

import lombok.SneakyThrows;

90

import java.io.*;

91

import java.net.URL;

92

93

public class FileProcessor {

94

95

@SneakyThrows

96

public String readFile(String filename) {

97

// No need to declare IOException in throws clause

98

return Files.readString(Paths.get(filename));

99

}

100

101

@SneakyThrows(UnsupportedEncodingException.class)

102

public String encodeUtf8(String text) {

103

// Only bypasses UnsupportedEncodingException

104

return URLEncoder.encode(text, "UTF-8");

105

}

106

107

@SneakyThrows({IOException.class, InterruptedException.class})

108

public String downloadContent(String url) {

109

HttpClient client = HttpClient.newHttpClient();

110

HttpRequest request = HttpRequest.newBuilder()

111

.uri(URI.create(url))

112

.build();

113

114

HttpResponse<String> response = client.send(request,

115

HttpResponse.BodyHandlers.ofString());

116

return response.body();

117

}

118

119

// Can be used with constructors too

120

@SneakyThrows

121

public FileProcessor(String configFile) {

122

Properties props = new Properties();

123

props.load(new FileInputStream(configFile)); // IOException sneakily thrown

124

}

125

}

126

127

// Usage - no try-catch required:

128

FileProcessor processor = new FileProcessor("config.properties");

129

String content = processor.readFile("data.txt");

130

String encoded = processor.encodeUtf8("hello world");

131

```

132

133

### @Synchronized Annotation

134

135

Generates synchronized methods using private lock objects instead of synchronizing on 'this', preventing external interference with locking.

136

137

```java { .api }

138

/**

139

* Synchronizes method execution using private lock objects.

140

* For instance methods: uses private $lock field

141

* For static methods: uses private static $LOCK field

142

* Lock fields are automatically generated if not present.

143

*/

144

@Target(ElementType.METHOD)

145

@interface Synchronized {

146

/**

147

* Name of the lock field to use for synchronization

148

* @return Field name for custom lock (empty = generate default)

149

*/

150

String value() default "";

151

}

152

```

153

154

**Usage Examples:**

155

156

```java

157

import lombok.Synchronized;

158

159

public class Counter {

160

private int count = 0;

161

private final Object customLock = new Object();

162

163

@Synchronized

164

public void increment() {

165

count++;

166

}

167

168

@Synchronized

169

public int getValue() {

170

return count;

171

}

172

173

@Synchronized("customLock")

174

public void reset() {

175

count = 0;

176

}

177

178

// Static method synchronization

179

private static int globalCounter = 0;

180

181

@Synchronized

182

public static void incrementGlobal() {

183

globalCounter++;

184

}

185

}

186

187

// Generated code equivalent:

188

// private final Object $lock = new Object();

189

// private static final Object $LOCK = new Object();

190

//

191

// public void increment() {

192

// synchronized(this.$lock) {

193

// count++;

194

// }

195

// }

196

//

197

// public static void incrementGlobal() {

198

// synchronized(Counter.$LOCK) {

199

// globalCounter++;

200

// }

201

// }

202

//

203

// public void reset() {

204

// synchronized(this.customLock) {

205

// count = 0;

206

// }

207

// }

208

```

209

210

### @Cleanup Annotation

211

212

Automatically generates try-finally blocks to ensure resource cleanup, similar to try-with-resources but more flexible.

213

214

```java { .api }

215

/**

216

* Ensures automatic resource cleanup by wrapping code in try-finally blocks.

217

* Calls the specified cleanup method in the finally block with null checks.

218

*/

219

@Target(ElementType.LOCAL_VARIABLE)

220

@interface Cleanup {

221

/**

222

* Name of the cleanup method to call

223

* @return Method name for cleanup (default: "close")

224

*/

225

String value() default "close";

226

}

227

```

228

229

**Usage Examples:**

230

231

```java

232

import lombok.Cleanup;

233

import java.io.*;

234

235

public class FileManager {

236

237

public void copyFile(String source, String target) throws IOException {

238

@Cleanup FileInputStream in = new FileInputStream(source);

239

@Cleanup FileOutputStream out = new FileOutputStream(target);

240

241

byte[] buffer = new byte[8192];

242

int length;

243

while ((length = in.read(buffer)) != -1) {

244

out.write(buffer, 0, length);

245

}

246

}

247

248

public void processDatabase() throws SQLException {

249

@Cleanup Connection conn = DriverManager.getConnection(url);

250

@Cleanup("close") PreparedStatement stmt = conn.prepareStatement(sql);

251

@Cleanup ResultSet rs = stmt.executeQuery();

252

253

while (rs.next()) {

254

processRow(rs);

255

}

256

}

257

258

// Custom cleanup method

259

public void useCustomResource() {

260

@Cleanup("shutdown") ExecutorService executor = Executors.newFixedThreadPool(4);

261

@Cleanup("release") Semaphore semaphore = new Semaphore(10);

262

263

// Use resources...

264

}

265

}

266

267

// Generated code equivalent for copyFile:

268

// public void copyFile(String source, String target) throws IOException {

269

// FileInputStream in = new FileInputStream(source);

270

// try {

271

// FileOutputStream out = new FileOutputStream(target);

272

// try {

273

// byte[] buffer = new byte[8192];

274

// int length;

275

// while ((length = in.read(buffer)) != -1) {

276

// out.write(buffer, 0, length);

277

// }

278

// } finally {

279

// if (out != null) out.close();

280

// }

281

// } finally {

282

// if (in != null) in.close();

283

// }

284

// }

285

```

286

287

### @With Annotation

288

289

Generates "wither" methods that create copies of immutable objects with one field changed, supporting functional programming patterns.

290

291

```java { .api }

292

/**

293

* Generates 'with' methods for creating modified copies of objects.

294

* Useful for immutable objects and functional programming patterns.

295

*/

296

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

297

@interface With {

298

/**

299

* Access level for the generated with method

300

* @return Access level for the with method (default: PUBLIC)

301

*/

302

AccessLevel value() default AccessLevel.PUBLIC;

303

304

/**

305

* Annotations to apply to the generated with method

306

* @return Array of annotations for the generated method

307

*/

308

AnyAnnotation[] onMethod() default {};

309

310

/**

311

* Annotations to apply to the generated method parameter

312

* @return Array of annotations for the generated parameter

313

*/

314

AnyAnnotation[] onParam() default {};

315

}

316

```

317

318

**Usage Examples:**

319

320

```java

321

import lombok.With;

322

import lombok.AllArgsConstructor;

323

import lombok.Getter;

324

import lombok.ToString;

325

326

@With

327

@AllArgsConstructor

328

@Getter

329

@ToString

330

public class Person {

331

private final String name;

332

private final int age;

333

private final String email;

334

private final String city;

335

}

336

337

// Usage:

338

Person original = new Person("John", 30, "john@example.com", "New York");

339

340

Person updated = original

341

.withAge(31)

342

.withCity("San Francisco")

343

.withEmail("john.doe@example.com");

344

345

System.out.println(original); // Original unchanged

346

System.out.println(updated); // New instance with changes

347

```

348

349

Selective field with methods:

350

```java

351

@AllArgsConstructor

352

@Getter

353

public class Configuration {

354

@With

355

private final String host;

356

357

@With

358

private final int port;

359

360

private final String secretKey; // No with method generated

361

362

@With(AccessLevel.PROTECTED)

363

private final boolean debugMode;

364

}

365

366

// Usage:

367

Configuration config = new Configuration("localhost", 8080, "secret", false);

368

Configuration prodConfig = config

369

.withHost("prod.example.com")

370

.withPort(443);

371

// .withSecretKey() - not available

372

// .withDebugMode() - protected access only

373

```

374

375

### @Locked Annotation

376

377

Advanced locking mechanism using ReadWriteLock for fine-grained concurrency control with separate read and write locks.

378

379

```java { .api }

380

/**

381

* Guards method execution with java.util.concurrent.locks.Lock.

382

* Uses ReadWriteLock for more sophisticated locking than @Synchronized.

383

*/

384

@Target(ElementType.METHOD)

385

@interface Locked {

386

/**

387

* Name of the lock field to use

388

* @return Field name for lock (empty = generate default)

389

*/

390

String value() default "";

391

392

/**

393

* Read lock annotation for concurrent read access

394

*/

395

@Target(ElementType.METHOD)

396

@interface Read {

397

/**

398

* Name of the ReadWriteLock field

399

* @return Field name for lock (empty = generate default)

400

*/

401

String value() default "";

402

}

403

404

/**

405

* Write lock annotation for exclusive write access

406

*/

407

@Target(ElementType.METHOD)

408

@interface Write {

409

/**

410

* Name of the ReadWriteLock field

411

* @return Field name for lock (empty = generate default)

412

*/

413

String value() default "";

414

}

415

}

416

```

417

418

**Usage Examples:**

419

420

```java

421

import lombok.Locked;

422

import java.util.concurrent.locks.ReadWriteLock;

423

import java.util.concurrent.locks.ReentrantReadWriteLock;

424

425

public class ThreadSafeCache {

426

private final Map<String, Object> cache = new HashMap<>();

427

private final ReadWriteLock cacheLock = new ReentrantReadWriteLock();

428

429

@Locked.Read

430

public Object get(String key) {

431

return cache.get(key);

432

}

433

434

@Locked.Read

435

public boolean containsKey(String key) {

436

return cache.containsKey(key);

437

}

438

439

@Locked.Write

440

public void put(String key, Object value) {

441

cache.put(key, value);

442

}

443

444

@Locked.Write

445

public void remove(String key) {

446

cache.remove(key);

447

}

448

449

@Locked.Read("cacheLock")

450

public Set<String> getKeys() {

451

return new HashSet<>(cache.keySet());

452

}

453

454

@Locked.Write("cacheLock")

455

public void clear() {

456

cache.clear();

457

}

458

}

459

460

// Generated code equivalent:

461

// public Object get(String key) {

462

// this.$lock.readLock().lock();

463

// try {

464

// return cache.get(key);

465

// } finally {

466

// this.$lock.readLock().unlock();

467

// }

468

// }

469

//

470

// public void put(String key, Object value) {

471

// this.$lock.writeLock().lock();

472

// try {

473

// cache.put(key, value);

474

// } finally {

475

// this.$lock.writeLock().unlock();

476

// }

477

// }

478

```

479

480

### Type Inference (val and var)

481

482

Local variable type inference with automatic final modifier application.

483

484

```java { .api }

485

/**

486

* Local variable type inference with final modifier

487

* Equivalent to 'final' + inferred type

488

*/

489

class val {} // Used as: lombok.val variable = expression;

490

491

/**

492

* Local variable type inference without final modifier

493

* Mutable variable with inferred type

494

*/

495

class var {} // Used as: lombok.var variable = expression;

496

```

497

498

**Usage Examples:**

499

500

```java

501

import lombok.val;

502

import lombok.var;

503

504

public class TypeInferenceExample {

505

506

public void demonstrateTypeInference() {

507

// val creates final variables with inferred types

508

val name = "John Doe"; // final String name

509

val age = 30; // final int age

510

val users = new ArrayList<User>(); // final ArrayList<User> users

511

val map = Map.of("key", "value"); // final Map<String, String> map

512

513

// name = "Jane"; // Compile error - final variable

514

515

// var creates mutable variables with inferred types

516

var counter = 0; // int counter

517

var buffer = new StringBuilder(); // StringBuilder buffer

518

var items = new LinkedList<String>(); // LinkedList<String> items

519

520

counter = 10; // OK - mutable

521

buffer.append("text"); // OK

522

523

// Complex type inference

524

val response = restTemplate.exchange(

525

"/api/users",

526

HttpMethod.GET,

527

null,

528

new ParameterizedTypeReference<List<User>>() {}

529

); // final ResponseEntity<List<User>> response

530

531

val optional = Optional.of("value")

532

.filter(s -> s.length() > 3)

533

.map(String::toUpperCase); // final Optional<String> optional

534

535

// Loop variable inference

536

val userList = Arrays.asList(new User("Alice"), new User("Bob"));

537

for (val user : userList) { // final User user

538

System.out.println(user.getName());

539

}

540

541

// Stream operations

542

val result = userList.stream()

543

.filter(u -> u.getAge() > 18)

544

.map(User::getName)

545

.collect(Collectors.toList()); // final List<String> result

546

}

547

}

548

```

549

550

## Type Definitions

551

552

```java { .api }

553

/**

554

* Access levels for generated methods

555

*/

556

public enum AccessLevel {

557

PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE, NONE

558

}

559

560

/**

561

* Placeholder for annotation arrays

562

*/

563

@interface AnyAnnotation {}

564

```