0
# Exception Handling
1
2
Micronaut Inject provides a comprehensive exception hierarchy for handling dependency injection errors, bean resolution failures, and configuration issues. Understanding these exceptions is crucial for proper error handling and debugging.
3
4
## Exception Hierarchy
5
6
### BeanContextException
7
8
Base exception for all bean context related errors.
9
10
```java { .api }
11
public class BeanContextException extends RuntimeException {
12
public BeanContextException(String message);
13
public BeanContextException(String message, Throwable cause);
14
}
15
```
16
17
### NoSuchBeanException
18
19
Thrown when a required bean cannot be found in the context.
20
21
```java { .api }
22
public class NoSuchBeanException extends BeanContextException {
23
public NoSuchBeanException(Class<?> beanType);
24
public NoSuchBeanException(Class<?> beanType, Qualifier<?> qualifier);
25
public NoSuchBeanException(String message);
26
27
public Class<?> getBeanType();
28
public Qualifier<?> getQualifier();
29
}
30
```
31
32
### NonUniqueBeanException
33
34
Thrown when multiple beans match a type but only one is expected.
35
36
```java { .api }
37
public class NonUniqueBeanException extends BeanContextException {
38
public NonUniqueBeanException(Class<?> beanType, Collection<BeanDefinition<?>> possibleCandidates);
39
40
public Class<?> getBeanType();
41
public Collection<BeanDefinition<?>> getPossibleCandidates();
42
}
43
```
44
45
### BeanInstantiationException
46
47
Thrown when bean instantiation fails.
48
49
```java { .api }
50
public class BeanInstantiationException extends BeanContextException {
51
public BeanInstantiationException(String message);
52
public BeanInstantiationException(String message, Throwable cause);
53
public BeanInstantiationException(BeanDefinition<?> beanDefinition, Throwable cause);
54
55
public BeanDefinition<?> getBeanDefinition();
56
}
57
```
58
59
### DependencyInjectionException
60
61
Thrown when dependency injection fails.
62
63
```java { .api }
64
public class DependencyInjectionException extends BeanContextException {
65
public DependencyInjectionException(String message);
66
public DependencyInjectionException(String message, Throwable cause);
67
public DependencyInjectionException(BeanDefinition<?> beanDefinition, Argument<?> argument, String message);
68
69
public BeanDefinition<?> getBeanDefinition();
70
public Argument<?> getArgument();
71
}
72
```
73
74
## Configuration Exceptions
75
76
### ConfigurationException
77
78
Thrown when configuration-related errors occur.
79
80
```java { .api }
81
public class ConfigurationException extends RuntimeException {
82
public ConfigurationException(String message);
83
public ConfigurationException(String message, Throwable cause);
84
}
85
```
86
87
## Common Error Scenarios
88
89
### Missing Bean Errors
90
91
```java
92
import io.micronaut.context.ApplicationContext;
93
import io.micronaut.context.exceptions.NoSuchBeanException;
94
95
public class MissingBeanExample {
96
public static void main(String[] args) {
97
try (ApplicationContext context = ApplicationContext.run()) {
98
99
try {
100
// This will throw NoSuchBeanException if UserService is not registered
101
UserService service = context.getBean(UserService.class);
102
service.createUser("John");
103
104
} catch (NoSuchBeanException e) {
105
System.err.println("Bean not found: " + e.getBeanType().getSimpleName());
106
System.err.println("Available alternatives:");
107
108
// Try to find similar beans
109
context.getBeanDefinitions(Object.class).stream()
110
.filter(def -> def.getBeanType().getSimpleName().contains("Service"))
111
.forEach(def -> System.err.println(" - " + def.getBeanType().getName()));
112
}
113
}
114
}
115
}
116
```
117
118
### Multiple Bean Candidates
119
120
```java
121
import io.micronaut.context.ApplicationContext;
122
import io.micronaut.context.exceptions.NonUniqueBeanException;
123
import io.micronaut.inject.qualifiers.Qualifiers;
124
125
// Multiple implementations
126
@Singleton
127
public class EmailNotificationService implements NotificationService {
128
// Email implementation
129
}
130
131
@Singleton
132
public class SmsNotificationService implements NotificationService {
133
// SMS implementation
134
}
135
136
public class NonUniqueBeanExample {
137
public static void main(String[] args) {
138
try (ApplicationContext context = ApplicationContext.run()) {
139
140
try {
141
// This will throw NonUniqueBeanException
142
NotificationService service = context.getBean(NotificationService.class);
143
144
} catch (NonUniqueBeanException e) {
145
System.err.println("Multiple beans found for: " + e.getBeanType().getSimpleName());
146
System.err.println("Candidates:");
147
148
for (BeanDefinition<?> candidate : e.getPossibleCandidates()) {
149
System.err.println(" - " + candidate.getBeanType().getName());
150
}
151
152
// Resolve using qualifier
153
NotificationService emailService = context.getBean(
154
NotificationService.class,
155
Qualifiers.byName("email")
156
);
157
}
158
}
159
}
160
}
161
```
162
163
### Bean Instantiation Failures
164
165
```java
166
import io.micronaut.context.ApplicationContext;
167
import io.micronaut.context.exceptions.BeanInstantiationException;
168
169
@Singleton
170
public class ProblematicService {
171
172
public ProblematicService() {
173
// This constructor throws an exception
174
if (System.currentTimeMillis() % 2 == 0) {
175
throw new RuntimeException("Random initialization failure");
176
}
177
}
178
}
179
180
public class InstantiationErrorExample {
181
public static void main(String[] args) {
182
try (ApplicationContext context = ApplicationContext.run()) {
183
184
try {
185
ProblematicService service = context.getBean(ProblematicService.class);
186
187
} catch (BeanInstantiationException e) {
188
System.err.println("Failed to create bean: " + e.getBeanDefinition().getBeanType());
189
System.err.println("Cause: " + e.getCause().getMessage());
190
191
// Log full stack trace for debugging
192
e.printStackTrace();
193
}
194
}
195
}
196
}
197
```
198
199
### Dependency Injection Failures
200
201
```java
202
import io.micronaut.context.ApplicationContext;
203
import io.micronaut.context.exceptions.DependencyInjectionException;
204
205
@Singleton
206
public class ServiceWithDependency {
207
208
@Inject
209
public ServiceWithDependency(NonExistentService dependency) {
210
// This will fail because NonExistentService doesn't exist
211
}
212
}
213
214
public class DependencyInjectionErrorExample {
215
public static void main(String[] args) {
216
try (ApplicationContext context = ApplicationContext.run()) {
217
218
try {
219
ServiceWithDependency service = context.getBean(ServiceWithDependency.class);
220
221
} catch (DependencyInjectionException e) {
222
System.err.println("Dependency injection failed for: " +
223
e.getBeanDefinition().getBeanType().getSimpleName());
224
225
if (e.getArgument() != null) {
226
System.err.println("Failed argument: " + e.getArgument().getName() +
227
" (" + e.getArgument().getType().getSimpleName() + ")");
228
}
229
230
System.err.println("Reason: " + e.getMessage());
231
}
232
}
233
}
234
}
235
```
236
237
## Configuration Error Handling
238
239
### Property Resolution Errors
240
241
```java
242
import io.micronaut.context.ApplicationContext;
243
import io.micronaut.context.exceptions.ConfigurationException;
244
import io.micronaut.context.env.Environment;
245
246
public class ConfigurationErrorExample {
247
public static void main(String[] args) {
248
try (ApplicationContext context = ApplicationContext.run()) {
249
Environment env = context.getEnvironment();
250
251
try {
252
// This will throw ConfigurationException if property is missing
253
String requiredValue = env.getRequiredProperty("required.property", String.class);
254
255
} catch (ConfigurationException e) {
256
System.err.println("Configuration error: " + e.getMessage());
257
258
// Show available properties for debugging
259
System.err.println("Available properties:");
260
env.getPropertySources().forEach(source -> {
261
System.err.println(" Source: " + source.getName());
262
});
263
}
264
}
265
}
266
}
267
```
268
269
### Configuration Properties Validation
270
271
```java
272
import io.micronaut.context.ApplicationContext;
273
import io.micronaut.context.exceptions.BeanInstantiationException;
274
import jakarta.validation.ConstraintViolationException;
275
276
@ConfigurationProperties("database")
277
public class DatabaseConfig {
278
279
@NotBlank
280
private String url;
281
282
@Min(1)
283
@Max(100)
284
private int maxConnections;
285
286
// Getters and setters
287
}
288
289
public class ValidationErrorExample {
290
public static void main(String[] args) {
291
// Run without proper configuration
292
try (ApplicationContext context = ApplicationContext.run()) {
293
294
try {
295
DatabaseConfig config = context.getBean(DatabaseConfig.class);
296
297
} catch (BeanInstantiationException e) {
298
if (e.getCause() instanceof ConstraintViolationException) {
299
ConstraintViolationException validationError =
300
(ConstraintViolationException) e.getCause();
301
302
System.err.println("Configuration validation failed:");
303
validationError.getConstraintViolations().forEach(violation -> {
304
System.err.println(" " + violation.getPropertyPath() +
305
": " + violation.getMessage());
306
});
307
}
308
}
309
}
310
}
311
}
312
```
313
314
## Error Recovery Strategies
315
316
### Graceful Degradation
317
318
```java
319
import io.micronaut.context.ApplicationContext;
320
import io.micronaut.context.exceptions.NoSuchBeanException;
321
322
@Singleton
323
public class ResilientService {
324
325
private final NotificationService notificationService;
326
private final boolean notificationEnabled;
327
328
@Inject
329
public ResilientService(ApplicationContext context) {
330
// Try to get notification service, fall back to null if not available
331
NotificationService service = null;
332
boolean enabled = false;
333
334
try {
335
service = context.getBean(NotificationService.class);
336
enabled = true;
337
} catch (NoSuchBeanException e) {
338
System.warn.println("Notification service not available, continuing without notifications");
339
}
340
341
this.notificationService = service;
342
this.notificationEnabled = enabled;
343
}
344
345
public void processOrder(Order order) {
346
// Core processing always works
347
order.setStatus(OrderStatus.PROCESSED);
348
349
// Optional notification
350
if (notificationEnabled && notificationService != null) {
351
try {
352
notificationService.sendOrderConfirmation(order);
353
} catch (Exception e) {
354
System.err.println("Failed to send notification, but order was processed: " + e.getMessage());
355
}
356
}
357
}
358
}
359
```
360
361
### Optional Dependencies
362
363
```java
364
import io.micronaut.context.ApplicationContext;
365
import java.util.Optional;
366
367
@Singleton
368
public class FlexibleService {
369
370
private final Optional<CacheService> cacheService;
371
private final Optional<MetricsService> metricsService;
372
373
@Inject
374
public FlexibleService(ApplicationContext context) {
375
this.cacheService = context.findBean(CacheService.class);
376
this.metricsService = context.findBean(MetricsService.class);
377
}
378
379
public String getData(String key) {
380
// Try cache first if available
381
if (cacheService.isPresent()) {
382
String cached = cacheService.get().get(key);
383
if (cached != null) {
384
metricsService.ifPresent(metrics -> metrics.increment("cache.hit"));
385
return cached;
386
}
387
}
388
389
// Fetch from database
390
String data = fetchFromDatabase(key);
391
392
// Cache if service available
393
cacheService.ifPresent(cache -> cache.put(key, data));
394
metricsService.ifPresent(metrics -> metrics.increment("cache.miss"));
395
396
return data;
397
}
398
}
399
```
400
401
### Retry and Fallback
402
403
```java
404
import io.micronaut.context.ApplicationContext;
405
import io.micronaut.context.exceptions.BeanInstantiationException;
406
407
@Singleton
408
public class RetryableService {
409
410
private ExternalService externalService;
411
private final int maxRetries = 3;
412
413
@PostConstruct
414
public void initialize() {
415
// Retry bean creation with backoff
416
for (int attempt = 1; attempt <= maxRetries; attempt++) {
417
try {
418
this.externalService = createExternalService();
419
break;
420
} catch (BeanInstantiationException e) {
421
System.err.println("Attempt " + attempt + " failed: " + e.getMessage());
422
423
if (attempt == maxRetries) {
424
System.err.println("All attempts failed, using fallback service");
425
this.externalService = new FallbackExternalService();
426
} else {
427
// Wait before retry
428
try {
429
Thread.sleep(1000 * attempt);
430
} catch (InterruptedException ie) {
431
Thread.currentThread().interrupt();
432
break;
433
}
434
}
435
}
436
}
437
}
438
}
439
```
440
441
## Debugging Bean Issues
442
443
### Bean Resolution Debugging
444
445
```java
446
import io.micronaut.context.ApplicationContext;
447
import io.micronaut.inject.BeanDefinition;
448
449
public class BeanDebuggingUtils {
450
451
public static void debugBeanResolution(ApplicationContext context, Class<?> beanType) {
452
System.out.println("Debugging bean resolution for: " + beanType.getSimpleName());
453
454
// Check if bean exists
455
boolean exists = context.containsBean(beanType);
456
System.out.println("Bean exists: " + exists);
457
458
if (!exists) {
459
// Show similar beans
460
System.out.println("Similar beans:");
461
context.getBeanDefinitions(Object.class).stream()
462
.filter(def -> def.getBeanType().getSimpleName().contains(beanType.getSimpleName()))
463
.forEach(def -> System.out.println(" - " + def.getBeanType().getName()));
464
} else {
465
// Show bean details
466
Collection<BeanDefinition<?>> definitions = context.getBeanDefinitions(beanType);
467
System.out.println("Found " + definitions.size() + " bean(s):");
468
469
for (BeanDefinition<?> def : definitions) {
470
System.out.println(" Bean: " + def.getBeanType().getName());
471
System.out.println(" Scope: " + (def.isSingleton() ? "Singleton" : "Prototype"));
472
System.out.println(" Constructor args: " + def.getConstructorArguments().size());
473
System.out.println(" Injected methods: " + def.getInjectedMethods().size());
474
System.out.println(" Injected fields: " + def.getInjectedFields().size());
475
}
476
}
477
}
478
479
public static void listAllBeans(ApplicationContext context) {
480
System.out.println("All registered beans:");
481
482
context.getBeanDefinitions(Object.class).stream()
483
.sorted((a, b) -> a.getBeanType().getName().compareTo(b.getBeanType().getName()))
484
.forEach(def -> {
485
System.out.println(" " + def.getBeanType().getName() +
486
" [" + (def.isSingleton() ? "Singleton" : "Prototype") + "]");
487
});
488
}
489
}
490
```
491
492
### Exception Chaining Analysis
493
494
```java
495
import io.micronaut.context.exceptions.BeanContextException;
496
497
public class ExceptionAnalyzer {
498
499
public static void analyzeBeanException(BeanContextException e) {
500
System.err.println("=== Bean Exception Analysis ===");
501
System.err.println("Exception type: " + e.getClass().getSimpleName());
502
System.err.println("Message: " + e.getMessage());
503
504
// Analyze specific exception types
505
if (e instanceof NoSuchBeanException) {
506
NoSuchBeanException nsbe = (NoSuchBeanException) e;
507
System.err.println("Missing bean type: " + nsbe.getBeanType());
508
if (nsbe.getQualifier() != null) {
509
System.err.println("Required qualifier: " + nsbe.getQualifier());
510
}
511
512
} else if (e instanceof NonUniqueBeanException) {
513
NonUniqueBeanException nube = (NonUniqueBeanException) e;
514
System.err.println("Ambiguous bean type: " + nube.getBeanType());
515
System.err.println("Candidates (" + nube.getPossibleCandidates().size() + "):");
516
nube.getPossibleCandidates().forEach(candidate ->
517
System.err.println(" - " + candidate.getBeanType().getName()));
518
519
} else if (e instanceof BeanInstantiationException) {
520
BeanInstantiationException bie = (BeanInstantiationException) e;
521
if (bie.getBeanDefinition() != null) {
522
System.err.println("Failed bean: " + bie.getBeanDefinition().getBeanType());
523
}
524
}
525
526
// Show cause chain
527
Throwable cause = e.getCause();
528
int level = 1;
529
while (cause != null) {
530
System.err.println("Cause " + level + ": " + cause.getClass().getSimpleName() +
531
" - " + cause.getMessage());
532
cause = cause.getCause();
533
level++;
534
}
535
}
536
}
537
```