E08150: dependency injection of a non-abstract component is not allowed, use an abstract base component
What went wrong
You're injecting a CONCRETE component type, but EK9's injection system works with abstract components for flexibility.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 111 (What are components in EK9?)
- ek9 -q 227 (How does EK9 validate dependency injection at compile time?)
- ek9 -q 231 (How do programs connect to applications for dependency in...)
- ek9 -q 228 (Why does registration order matter in EK9 applications?)
- ek9 -q 229 (How does EK9 prevent circular dependencies?)
Rationale
Abstract injection separates contract from implementation. Different applications can wire different concrete components to the same abstract type (e.g., prod vs test configurations).
How to fix it
- Define abstract base component
- Inject abstract type with '!'
- Register concrete in application with 'register ... as ...'
Common causes
- Injecting implementation instead of abstraction
- Not using abstract component pattern
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08150: dependency injection of a non-abstract component is not allowed, use an abstract base component
#!ek9 defines module error.e08150.bad defines function report() <- summary as String? timekeeper as Timekeeper! summary: "It is " + timekeeper.now() defines component Timekeeper now() <- time as String: "noon"
Fixed: Make the concrete component directly; inject only an abstract one
#!ek9 defines module error.e08150.good.fix defines function report() <- summary as String? timekeeper <- Timekeeper() summary: "It is " + timekeeper.now() defines component Timekeeper now() <- time as String: "noon"
Fixed: Inject the abstract component; the application registers the concrete one
#!ek9 defines module error.e08150.good defines component Timekeeper as abstract now() as abstract <- time as String? NoonTimekeeper is Timekeeper override now() <- time as String: "noon" defines application TimeApp register NoonTimekeeper() as Timekeeper defines program Report() with application of TimeApp timekeeper as Timekeeper! Stdout().println("It is " + timekeeper.now())
Questions and answers
These Q&A entries show E08150 and its fix:
- Q111: What are components in EK9?
- Q227: How does EK9 validate dependency injection at compile time?
- Q228: Why does registration order matter in EK9 applications?
- Q229: How does EK9 prevent circular dependencies?
- Q231: How do programs connect to applications for dependency injection?
- Q232: How do components inject other components in EK9?
- Q233: Can dynamic classes use dependency injection in EK9?
- Q234: What is the lifecycle of injected components in EK9?
- Q324: What is the EK9 equivalent of Spring @Autowired?
- Q325: What is the EK9 equivalent of Spring @Component and @Service?
- Q326: What is the EK9 equivalent of Spring @Bean and @Configuration?
- Q328: How does EK9 DI compare to Quarkus build-time injection?
- Q329: How does EK9 DI compare to Google Guice modules?
- Q330: Does EK9 support DI scopes like singleton, prototype, and request?
- Q331: How do I test components with injected dependencies?
- Q332: What is the runtime overhead of EK9 DI compared to frameworks?
- Q337: Can I use aspects for transactions like Spring @Transactional?
- Q667: Why must injected components be abstract types?
- Q1112: Inject a Logger dependency into a component's field using the ! suffix.
- Q1183: Register a concrete Logger as an abstract Logger type for dependency injection.