quarkusio/quarkus · error · DefinitionException

Decorator declares a disposer method: ${decoratorClass}

Error message

Decorator declares a disposer method: ${decoratorClass}

What it means

Build-time CDI definition error: while walking the decorator's class hierarchy, ArC found a method with a @Disposes parameter. Disposer methods belong to producer classes, not decorators; the decorator class in the message declares one and deployment fails.

Source

Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Decorators.java:168

            }
        }

        checkDecoratorFieldsAndMethods(decoratorClass, beanDeployment);

        return new DecoratorInfo(decoratorClass, beanDeployment, delegateInjectionPoint,
                decoratedTypes, injections, priority);
    }

    private static void checkDecoratorFieldsAndMethods(ClassInfo decoratorClass, BeanDeployment beanDeployment) {
        ClassInfo aClass = decoratorClass;
        while (aClass != null) {
            for (MethodInfo method : aClass.methods()) {
                if (beanDeployment.hasAnnotation(method, DotNames.PRODUCES)) {
                    throw new DefinitionException("Decorator declares a producer method: " + decoratorClass);
                }
                // the following 3 checks rely on the annotation store returning parameter annotations for methods
                if (beanDeployment.hasAnnotation(method, DotNames.DISPOSES)) {
                    throw new DefinitionException("Decorator declares a disposer method: " + decoratorClass);
                }
                if (beanDeployment.hasAnnotation(method, DotNames.OBSERVES)) {
                    throw new DefinitionException("Decorator declares an observer method: " + decoratorClass);
                }
                if (beanDeployment.hasAnnotation(method, DotNames.OBSERVES_ASYNC)) {
                    throw new DefinitionException("Decorator declares an async observer method: " + decoratorClass);
                }
            }

            for (FieldInfo field : aClass.fields()) {
                if (beanDeployment.hasAnnotation(field, DotNames.PRODUCES)) {
                    throw new DefinitionException("Decorator declares a producer field: " + decoratorClass);
                }
            }

            DotName superClass = aClass.superName();
            aClass = superClass != null && !superClass.equals(DotNames.OBJECT)
                    ? getClassByName(beanDeployment.getBeanArchiveIndex(), superClass)

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove the @Disposes parameter/method from the decorator.
  2. Move disposal to the bean that declares the corresponding @Produces method.
  3. Split responsibilities: keep the decorator only for interception logic.
  4. Audit superclasses, since the check walks the whole hierarchy.

Example fix

// before
@Decorator
public class D implements Greeter {
    void dispose(@Disposes Resource r) { r.close(); }
}

// after
@Decorator
public class D implements Greeter { /* no disposer */ }
Defensive patterns

Strategy: validation

Validate before calling

if (decoratorClass.getAnnotation(jakarta.decorator.Decorator.class) != null)
    for (Method m : decoratorClass.getMethods())
        if (Arrays.stream(m.getParameters()).anyMatch(p -> p.isAnnotationPresent(jakarta.enterprise.inject.Disposes.class)))
            throw new IllegalStateException("Decorator cannot declare disposer: " + m);

Prevention

When it happens

Trigger: A @Decorator class contains a method with a @Disposes-annotated parameter, found during createDecorator via checkDecoratorFieldsAndMethods.

Common situations: Merging disposer logic from a producer bean into a decorator; leftover disposer after converting a class into a decorator; copying a disposer method into the decorator for convenience.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/a3d97a97f01435c9. Report an issue: GitHub.