quarkusio/quarkus · error · DefinitionException
Initializer method may not be generic (declare type paramete
Error message
Initializer method may not be generic (declare type parameters):
What it means
ArC forbids initializer/injector methods (non-constructor methods used for injection) from declaring type parameters. Generic constructors are allowed, but a generic initializer method cannot be resolved at bean creation. This is a CDI spec definition rule enforced at build time.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Injection.java:338
InjectionPointModifier transformer, boolean skipConstructors, Set<MethodOverrideKey> seenMethods) {
List<Injection> injections = new ArrayList<>();
List<AnnotationInstance> injectAnnotations = getAllInjectionPoints(beanDeployment, classInfo, DotNames.INJECT,
skipConstructors, seenMethods);
for (AnnotationInstance injectAnnotation : injectAnnotations) {
AnnotationTarget injectTarget = injectAnnotation.target();
switch (injectAnnotation.target().kind()) {
case FIELD:
injections.add(new Injection(injectTarget, Collections.singletonList(
InjectionPointInfo.fromField(injectTarget.asField(), beanClass, beanDeployment, transformer))));
break;
case METHOD:
// the spec doesn't forbid generic bean constructors and Weld is fine with them too
if (!injectTarget.asMethod().isConstructor()
&& !injectTarget.asMethod().typeParameters().isEmpty()) {
throw new DefinitionException(
"Initializer method may not be generic (declare type parameters): " + injectTarget);
}
injections.add(new Injection(injectTarget,
InjectionPointInfo.fromMethod(injectTarget.asMethod(), beanClass, beanDeployment, transformer)));
break;
default:
LOGGER.warn("Unsupported @Inject target ignored: " + injectAnnotation.target());
continue;
}
}
// if the class has no no-arg constructor and has a single non no-arg constructor that is not annotated with @Inject,
// the class is not a non-static inner or a superclass of a bean we consider that constructor as an injection
if (beanClass.equals(classInfo)) {
final boolean isNonStaticInnerClass = classInfo.name().isInner()
&& !Modifier.isStatic(classInfo.flags());
if (!isNonStaticInnerClass && !hasConstructorInjection(injections) && !beanClass.hasNoArgsConstructor()) {
List<MethodInfo> nonNoargConstrs = new ArrayList<>();View on GitHub (pinned to e1c734241f)
Solutions
- Remove the type parameters from the initializer method and use concrete types
- Move the generic logic into a plain helper method called from the initializer
- Inject via constructor instead, since generic constructors are permitted
Example fix
// before
@Inject
<T> void init(T value) {}
// after
@Inject
void init(String value) {} Defensive patterns
Strategy: validation
Validate before calling
for (Method m : MyBean.class.getDeclaredMethods()) {
if (m.isAnnotationPresent(Inject.class) && m.getTypeParameters().length > 0) {
throw new IllegalStateException("Generic initializer: " + m);
}
} Prevention
- Never add <T> type parameters to @Inject methods
- Use concrete types in initializer signatures
- Prefer constructor injection, which may be generic
When it happens
Trigger: Declaring an @Inject-annotated (or bean-defining) non-constructor method with type parameters, e.g. <T> void init(T x); found while building injections for a class bean via Injection.forClassBean.
Common situations: Adding generics to an existing @Inject setter for type-safety; refactoring a utility-style generic method into a bean initializer; migrating code where Weld previously surfaced a similar error.
Related errors
- InterceptionProxy parameter must be a parameterized type: ${
- Producer field type is a parameterized type with a type vari
- Declaring class of a managed bean is generic, its scope must
- Type of injected Bean<T> does not match the type of the bean
- Injected @Intercepted Bean<?> has to use unbound wildcard as
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/03d415ba199450ea.
Report an issue: GitHub.