or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

default-annotations.mdindex.mdnull-safety.mdresource-management.mdreturn-value-checking.mdtesting-annotations.mdwarning-suppression.md

return-value-checking.mddocs/

0

# Return Value Checking

1

2

Enforce that method return values are checked by callers to prevent ignored error conditions and resource leaks. This is particularly important for methods that return status codes, validation results, or resource handles.

3

4

## Capabilities

5

6

### CheckReturnValue Annotation

7

8

Marks methods whose return values should always be checked when invoking the method.

9

10

```java { .api }

11

/**

12

* This annotation is used to denote a method whose return value should always

13

* be checked when invoking the method.

14

*

15

* The checker treats this annotation as inherited by overriding methods.

16

*/

17

@Documented

18

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

19

@Retention(RetentionPolicy.CLASS)

20

@interface CheckReturnValue {

21

22

/**

23

* @deprecated Use confidence() instead

24

*/

25

@Deprecated

26

Priority priority() default Priority.MEDIUM;

27

28

/**

29

* The confidence level for this check

30

*/

31

Confidence confidence() default Confidence.MEDIUM;

32

33

/**

34

* A textual explanation of why the return value should be checked

35

*/

36

String explanation() default "";

37

}

38

```

39

40

**Usage Examples:**

41

42

```java

43

public class ConnectionManager {

44

45

// Return value must be checked - connection might fail

46

@CheckReturnValue(explanation = "Connection status must be verified before use")

47

public boolean connect() {

48

try {

49

establishConnection();

50

return true;

51

} catch (Exception e) {

52

return false;

53

}

54

}

55

56

// File operations should check success status

57

@CheckReturnValue(explanation = "File operations may fail and should be verified")

58

public boolean saveToFile(@NonNull String filename, @NonNull String data) {

59

try {

60

Files.write(Paths.get(filename), data.getBytes());

61

return true;

62

} catch (IOException e) {

63

logger.error("Failed to save file: " + filename, e);

64

return false;

65

}

66

}

67

68

// Resource creation must be checked

69

@CheckReturnValue(explanation = "Resource acquisition may fail")

70

public InputStream openResource(@NonNull String resourcePath) {

71

return getClass().getResourceAsStream(resourcePath); // May return null

72

}

73

74

// Validation results must be examined

75

@CheckReturnValue(explanation = "Validation errors must be handled")

76

public ValidationResult validateInput(@NonNull String input) {

77

return validator.validate(input);

78

}

79

}

80

81

// Proper usage - checking return values

82

public class ServiceClient {

83

84

public void performOperation() {

85

ConnectionManager manager = new ConnectionManager();

86

87

// GOOD: Check return value

88

boolean connected = manager.connect();

89

if (!connected) {

90

throw new RuntimeException("Failed to connect");

91

}

92

93

// GOOD: Check file operation result

94

boolean saved = manager.saveToFile("output.txt", "data");

95

if (!saved) {

96

logger.warn("Failed to save output file");

97

}

98

99

// GOOD: Check resource acquisition

100

InputStream stream = manager.openResource("/config.properties");

101

if (stream == null) {

102

throw new RuntimeException("Configuration file not found");

103

}

104

105

// GOOD: Handle validation results

106

ValidationResult result = manager.validateInput(userInput);

107

if (!result.isValid()) {

108

displayErrors(result.getErrors());

109

return;

110

}

111

}

112

113

public void badUsage() {

114

ConnectionManager manager = new ConnectionManager();

115

116

// BAD: Ignoring return value - SpotBugs will warn

117

manager.connect(); // Warning: return value should be checked

118

119

// BAD: Not checking file operation

120

manager.saveToFile("output.txt", "data"); // Warning: return value ignored

121

}

122

}

123

```

124

125

### Constructor Return Value Checking

126

127

The annotation can also be applied to constructors to indicate that construction success should be verified.

128

129

```java { .api }

130

public class ResourceHandle {

131

132

// Constructor that may fail - check for null or use factory method

133

@CheckReturnValue(explanation = "Resource creation may fail")

134

public ResourceHandle(@NonNull String resourceId) {

135

if (!isValidResource(resourceId)) {

136

throw new IllegalArgumentException("Invalid resource: " + resourceId);

137

}

138

// Initialize resource

139

}

140

141

// Factory method with return value checking

142

@CheckReturnValue(explanation = "Resource creation may fail, returns null on failure")

143

public static ResourceHandle tryCreate(@NonNull String resourceId) {

144

try {

145

return new ResourceHandle(resourceId);

146

} catch (Exception e) {

147

return null; // Caller must check for null

148

}

149

}

150

}

151

152

// Usage

153

public void createResource() {

154

// GOOD: Using exception-based constructor (automatic checking)

155

try {

156

ResourceHandle handle = new ResourceHandle("resource-123");

157

useResource(handle);

158

} catch (IllegalArgumentException e) {

159

logger.error("Failed to create resource", e);

160

}

161

162

// GOOD: Checking factory method return value

163

ResourceHandle handle = ResourceHandle.tryCreate("resource-456");

164

if (handle != null) {

165

useResource(handle);

166

} else {

167

logger.error("Failed to create resource");

168

}

169

}

170

```

171

172

### Method Overriding and Inheritance

173

174

The `@CheckReturnValue` annotation is inherited by overriding methods.

175

176

```java { .api }

177

public abstract class BaseService {

178

179

@CheckReturnValue(explanation = "Service operations may fail")

180

public abstract boolean performOperation();

181

}

182

183

public class DatabaseService extends BaseService {

184

185

// Inherits @CheckReturnValue from parent method

186

@Override

187

public boolean performOperation() {

188

try {

189

executeQuery();

190

return true;

191

} catch (SQLException e) {

192

return false;

193

}

194

}

195

}

196

197

// Usage - must check return value even when calling through subclass

198

public void useService() {

199

DatabaseService service = new DatabaseService();

200

201

// GOOD: Checking inherited return value requirement

202

boolean success = service.performOperation();

203

if (!success) {

204

handleFailure();

205

}

206

207

// BAD: Ignoring return value - SpotBugs will warn

208

service.performOperation(); // Warning: return value should be checked

209

}

210

```

211

212

### Integration with Confidence Levels

213

214

Use confidence levels to indicate how important return value checking is.

215

216

```java { .api }

217

public class SecurityService {

218

219

// High confidence - critical security operation

220

@CheckReturnValue(

221

confidence = Confidence.HIGH,

222

explanation = "Authentication failures must be handled"

223

)

224

public boolean authenticate(@NonNull String username, @NonNull String password) {

225

return authProvider.validate(username, password);

226

}

227

228

// Medium confidence - important but not critical

229

@CheckReturnValue(

230

confidence = Confidence.MEDIUM,

231

explanation = "Cache operations should be verified"

232

)

233

public boolean cacheData(@NonNull String key, @NonNull Object data) {

234

return cache.put(key, data);

235

}

236

237

// Low confidence - nice to check but not essential

238

@CheckReturnValue(

239

confidence = Confidence.LOW,

240

explanation = "Logging failures are typically non-critical"

241

)

242

public boolean logEvent(@NonNull String event) {

243

return logger.log(event);

244

}

245

}

246

```

247

248

## Common Use Cases

249

250

### Status Code Returns

251

252

```java

253

@CheckReturnValue(explanation = "HTTP status must be verified")

254

public int makeHttpRequest(@NonNull String url) {

255

// Returns HTTP status code

256

return httpClient.get(url).getStatusCode();

257

}

258

```

259

260

### Resource Acquisition

261

262

```java

263

@CheckReturnValue(explanation = "File handle may be null if file doesn't exist")

264

public FileInputStream openFile(@NonNull String filename) {

265

try {

266

return new FileInputStream(filename);

267

} catch (FileNotFoundException e) {

268

return null;

269

}

270

}

271

```

272

273

### Validation Results

274

275

```java

276

@CheckReturnValue(explanation = "Validation errors must be handled")

277

public boolean isValidEmail(@NonNull String email) {

278

return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");

279

}

280

```

281

282

### Lock Acquisition

283

284

```java

285

@CheckReturnValue(explanation = "Lock acquisition may fail or timeout")

286

public boolean tryLock(long timeout, TimeUnit unit) {

287

try {

288

return lock.tryLock(timeout, unit);

289

} catch (InterruptedException e) {

290

Thread.currentThread().interrupt();

291

return false;

292

}

293

}

294

```

295

296

## Best Practices

297

298

1. **Use meaningful explanations**: Provide clear reasons why the return value should be checked

299

2. **Apply to failure-prone operations**: Focus on methods that can fail or return error indicators

300

3. **Consider inheritance**: Remember that annotations are inherited by overriding methods

301

4. **Use appropriate confidence levels**: Match confidence to the criticality of checking the return value

302

5. **Document alternatives**: If return value checking isn't possible, document exception-based alternatives

303

6. **Consistent application**: Apply consistently across similar methods in your API