quarkusio/quarkus · error · RuntimeException

Usage of '@Inject' is not allowed in 'jakarta.ws.rs.core.App

Error message

Usage of '@Inject' is not allowed in 'jakarta.ws.rs.core.Application' classes. Offending class is '${jakartaRestApplicationClass.name()}'

What it means

Quarkus evaluates a JAX-RS Application class at build time (getAllowedClasses instantiates it directly, outside CDI) to determine which classes it selects. Because the instance is created by plain reflection rather than the CDI container, @Inject fields would not be populated; to fail fast instead of producing nulls, the processor rejects Application classes annotated with @Inject with this RuntimeException.

Source

Thrown at extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java:1092

            annotatedProviders.removeAll(excludedClasses);
        } else {
            annotatedProviders.retainAll(allowedClasses);
        }
        providers.addAll(annotatedProviders);
        contributedProviders.addAll(annotatedProviders);
        return new JaxrsProvidersToRegisterBuildItem(
                providers, contributedProviders, annotatedProviders, jaxrsProvidersToRegisterBuildItem.useBuiltIn());
    }

    /**
     * @return the set of classes returned by the methods {@link Application#getClasses()} and
     *         {@link Application#getSingletons()}.
     */
    private Set<String> getAllowedClasses(ClassInfo jakartaRestApplicationClass) {
        final Set<String> allowedClasses = new HashSet<>();
        Application application;
        if (jakartaRestApplicationClass.annotationsMap().containsKey(ResteasyDotNames.CDI_INJECT)) {
            throw new RuntimeException(
                    "Usage of '@Inject' is not allowed in 'jakarta.ws.rs.core.Application' classes. Offending class is '"
                            + jakartaRestApplicationClass.name() + "'");
        }

        String applicationClass = jakartaRestApplicationClass.name().toString();
        try {
            Class<?> appClass = Thread.currentThread().getContextClassLoader().loadClass(applicationClass);
            application = (Application) appClass.getConstructor().newInstance();
            Set<Class<?>> classes = application.getClasses();
            if (!classes.isEmpty()) {
                for (Class<?> klass : classes) {
                    allowedClasses.add(klass.getName());
                }
            }
            classes = application.getSingletons().stream().map(Object::getClass).collect(Collectors.toSet());
            if (!classes.isEmpty()) {
                for (Class<?> klass : classes) {
                    allowedClasses.add(klass.getName());

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove all @Inject annotations from the Application class; return classes/set from getClasses() statically.
  2. If you need injectable config, read it via ConfigProvider.getConfig() or @ConfigProperty on the resource classes instead.
  3. Rely on Quarkus annotation-based discovery (@Path, @Provider) and drop the Application class, or use the classes config properties to select resources.

Example fix

// before
public class MyApp extends Application {
    @Inject
    SomeService service;
    @Override public Set<Class<?>> getClasses() { return Set.of(service.endpoint()); }
}

// after
public class MyApp extends Application {
    @Override public Set<Class<?>> getClasses() { return Set.of(MyEndpoint.class); }
}
Defensive patterns

Strategy: validation

Validate before calling

static void assertNoInject(Class<?> appClass) {
    for (Field f : appClass.getDeclaredFields()) {
        if (f.isAnnotationPresent(jakarta.inject.Inject.class))
            throw new IllegalStateException("@Inject not allowed in Application class: " + appClass.getName());
    }
}

Type guard

static boolean isCdiFreeApplication(Class<?> c) {
    return Arrays.stream(c.getDeclaredFields())
        .noneMatch(f -> f.isAnnotationPresent(jakarta.inject.Inject.class));
}

Try / catch

// Deployment-time failure: cannot be caught at runtime.
// Detect in CI with a unit test scanning the Application class for @Inject before building.

Prevention

When it happens

Trigger: Declaring a class extending jakarta.ws.rs.core.Application whose fields or methods are annotated with jakarta.inject.Inject (detected via the CDI_INJECT annotation in the build index) while the RESTEasy Classic server deployment runs getAllowedClasses for it.

Common situations: Developers porting a Spring/CDI-style Application class and injecting a config bean or service to compute getClasses()/getSingletons(); quarkus-arc enforcing that Application classes are not beans.

Related errors


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