or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdexceptions.mdindex.md

exceptions.mddocs/

0

# Exception Handling

1

2

Groovy Contracts provides specialized exception classes for different types of contract violations and utilities for tracking multiple violations during contract evaluation.

3

4

## Exception Hierarchy

5

6

### AssertionViolation (Abstract Base)

7

8

```groovy { .api }

9

abstract class AssertionViolation extends AssertionError {

10

protected AssertionViolation()

11

protected AssertionViolation(Object o)

12

protected AssertionViolation(boolean b)

13

protected AssertionViolation(char c)

14

protected AssertionViolation(int i)

15

protected AssertionViolation(long l)

16

protected AssertionViolation(float v)

17

protected AssertionViolation(double v)

18

}

19

```

20

21

Abstract base class for all contract assertion violations. Automatically registers with `ViolationTracker` upon instantiation to support chronological violation tracking.

22

23

**Features:**

24

- Extends `AssertionError` for integration with Java assertion system

25

- Automatic registration with violation tracker

26

- Protected constructors for all primitive types and Object

27

28

## Specific Violation Types

29

30

### PreconditionViolation

31

32

```groovy { .api }

33

class PreconditionViolation extends AssertionViolation {

34

PreconditionViolation()

35

PreconditionViolation(Object o)

36

PreconditionViolation(boolean b)

37

PreconditionViolation(char c)

38

PreconditionViolation(int i)

39

PreconditionViolation(long l)

40

PreconditionViolation(float v)

41

PreconditionViolation(double v)

42

}

43

```

44

45

Thrown when a `@Requires` annotation condition fails. Indicates that a method was called with invalid arguments or in an invalid state.

46

47

**Usage Example:**

48

49

```groovy

50

@Requires({ amount > 0 })

51

void withdraw(BigDecimal amount) {

52

balance -= amount

53

}

54

55

// Calling withdraw(-100) will throw PreconditionViolation

56

```

57

58

**Catching Precondition Violations:**

59

60

```groovy

61

try {

62

account.withdraw(new BigDecimal("-100"))

63

} catch (PreconditionViolation e) {

64

println "Invalid withdrawal amount: ${e.message}"

65

}

66

```

67

68

### PostconditionViolation

69

70

```groovy { .api }

71

class PostconditionViolation extends AssertionViolation {

72

PostconditionViolation()

73

PostconditionViolation(Object o)

74

PostconditionViolation(boolean b)

75

PostconditionViolation(char c)

76

PostconditionViolation(int i)

77

PostconditionViolation(long l)

78

PostconditionViolation(float v)

79

PostconditionViolation(double v)

80

}

81

```

82

83

Thrown when an `@Ensures` annotation condition fails. Indicates that a method did not fulfill its guaranteed postcondition.

84

85

**Usage Example:**

86

87

```groovy

88

@Ensures({ result > 0 })

89

int calculateAge(Date birthDate) {

90

// Bug: might return negative value for future dates

91

return (new Date().time - birthDate.time) / (365 * 24 * 60 * 60 * 1000)

92

}

93

94

// Method will throw PostconditionViolation if it returns negative age

95

```

96

97

**Catching Postcondition Violations:**

98

99

```groovy

100

try {

101

int age = person.calculateAge(futureDate)

102

} catch (PostconditionViolation e) {

103

println "Method failed to satisfy postcondition: ${e.message}"

104

}

105

```

106

107

### ClassInvariantViolation

108

109

```groovy { .api }

110

class ClassInvariantViolation extends AssertionViolation {

111

ClassInvariantViolation()

112

ClassInvariantViolation(Object o)

113

ClassInvariantViolation(boolean b)

114

ClassInvariantViolation(char c)

115

ClassInvariantViolation(int i)

116

ClassInvariantViolation(long l)

117

ClassInvariantViolation(float v)

118

ClassInvariantViolation(double v)

119

}

120

```

121

122

Thrown when an `@Invariant` annotation condition fails. Indicates that an object's state became invalid during construction or method execution.

123

124

**Usage Example:**

125

126

```groovy

127

@Invariant({ balance >= 0 })

128

class BankAccount {

129

private BigDecimal balance = BigDecimal.ZERO

130

131

void withdraw(BigDecimal amount) {

132

balance -= amount // Might violate invariant

133

}

134

}

135

136

// Creating account or calling withdraw might throw ClassInvariantViolation

137

```

138

139

**Catching Invariant Violations:**

140

141

```groovy

142

try {

143

BankAccount account = new BankAccount()

144

account.withdraw(new BigDecimal("1000"))

145

} catch (ClassInvariantViolation e) {

146

println "Object state became invalid: ${e.message}"

147

}

148

```

149

150

### CircularAssertionCallException

151

152

```groovy { .api }

153

class CircularAssertionCallException extends RuntimeException {

154

CircularAssertionCallException()

155

CircularAssertionCallException(String s)

156

CircularAssertionCallException(String s, Throwable throwable)

157

CircularAssertionCallException(Throwable throwable)

158

}

159

```

160

161

Thrown when contract evaluation results in circular method calls, preventing infinite recursion. Unlike other contract violations, this extends `RuntimeException` rather than `AssertionViolation`.

162

163

**Usage Example:**

164

165

```groovy

166

@Invariant({ isValid() })

167

class CircularExample {

168

boolean isValid() {

169

return someCondition() // If this triggers invariant check, causes circular call

170

}

171

172

void doSomething() {

173

// Method call will trigger invariant check

174

}

175

}

176

```

177

178

**Preventing Circular Calls:**

179

180

```groovy

181

@Invariant({ balance >= 0 }) // Simple field check, no method calls

182

class SafeAccount {

183

private BigDecimal balance = BigDecimal.ZERO

184

185

boolean isValid() {

186

return true // Don't call methods in contracts

187

}

188

}

189

```

190

191

## Violation Tracking

192

193

### ViolationTracker

194

195

```groovy { .api }

196

class ViolationTracker {

197

static final ThreadLocal<ViolationTracker> INSTANCE

198

199

static void init()

200

static void deinit()

201

static boolean violationsOccurred()

202

static void rethrowFirst()

203

static void rethrowLast()

204

205

void track(AssertionViolation assertionViolation)

206

boolean hasViolations()

207

AssertionViolation first()

208

AssertionViolation last()

209

}

210

```

211

212

Thread-local utility for tracking multiple contract violations in chronological order. Used internally by the contract system to manage violation reporting.

213

214

**Important**: The `INSTANCE.get()` method can return `null` if no tracker has been initialized for the current thread. Most static methods include null checking, but direct access requires manual null checking.

215

216

**Static Methods:**

217

218

**`init()`**: Initialize violation tracker for current thread

219

```groovy

220

ViolationTracker.init()

221

```

222

223

**`deinit()`**: Remove violation tracker from current thread

224

```groovy

225

ViolationTracker.deinit()

226

```

227

228

**`violationsOccurred()`**: Check if any violations occurred

229

```groovy

230

// Safe to call - includes null checking

231

if (ViolationTracker.violationsOccurred()) {

232

// Handle violations

233

}

234

```

235

236

**`rethrowFirst()`**: Rethrow the first violation that occurred

237

```groovy

238

ViolationTracker.rethrowFirst()

239

```

240

241

**`rethrowLast()`**: Rethrow the most recent violation

242

```groovy

243

ViolationTracker.rethrowLast()

244

```

245

246

**Instance Methods:**

247

248

**`track(AssertionViolation)`**: Track a violation (called automatically)

249

**`hasViolations()`**: Check if tracker has recorded violations

250

**`first()`**: Get the first violation

251

**`last()`**: Get the most recent violation

252

253

## Exception Handling Patterns

254

255

### Comprehensive Exception Handling

256

257

```groovy

258

try {

259

performContractedOperation()

260

} catch (PreconditionViolation e) {

261

// Handle invalid input or state

262

log.error("Invalid precondition: ${e.message}")

263

return errorResponse("Invalid parameters provided")

264

} catch (PostconditionViolation e) {

265

// Handle implementation bugs

266

log.error("Method failed postcondition: ${e.message}")

267

return errorResponse("Internal processing error")

268

} catch (ClassInvariantViolation e) {

269

// Handle object state corruption

270

log.error("Object invariant violated: ${e.message}")

271

return errorResponse("Object state became invalid")

272

} catch (CircularAssertionCallException e) {

273

// Handle contract design issues

274

log.error("Circular contract evaluation: ${e.message}")

275

return errorResponse("Contract evaluation error")

276

}

277

```

278

279

### Assertion-Based Exception Handling

280

281

```groovy

282

// Contracts work with Java assertion system

283

try {

284

contractedMethod()

285

} catch (AssertionError e) {

286

if (e instanceof AssertionViolation) {

287

// Handle contract violations specifically

288

handleContractViolation((AssertionViolation) e)

289

} else {

290

// Handle other assertion failures

291

handleGeneralAssertion(e)

292

}

293

}

294

```

295

296

### Production Error Handling

297

298

```groovy

299

// Disable assertions in production to avoid contract exceptions

300

// Use JVM flags: -da (disable assertions)

301

// Or package-specific: -da:com.example.contracts.*

302

303

class ProductionService {

304

@Requires({ input != null })

305

@Ensures({ result != null })

306

String processInput(String input) {

307

// In production with -da, contracts won't throw exceptions

308

// But defensive programming is still recommended

309

if (input == null) {

310

throw new IllegalArgumentException("Input cannot be null")

311

}

312

313

String result = doProcessing(input)

314

315

if (result == null) {

316

throw new IllegalStateException("Processing failed")

317

}

318

319

return result

320

}

321

}

322

```

323

324

## Best Practices

325

326

### Exception Handling Guidelines

327

328

1. **Catch specific exceptions**: Handle each violation type appropriately

329

2. **Log contract violations**: Include detailed information for debugging

330

3. **Use assertions for development**: Enable during testing and development

331

4. **Control production behavior**: Use JVM assertion flags to control contract checking

332

5. **Combine with defensive programming**: Don't rely solely on contracts for validation

333

334

### Debugging Contract Violations

335

336

1. **Enable assertion messages**: Use descriptive expressions in contracts

337

2. **Use violation tracker**: Access chronological violation information

338

3. **Test contract scenarios**: Verify both success and failure cases

339

4. **Review inheritance hierarchies**: Check combined contract behavior