quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.78k stars 2.68k forks source link

RESTEasy Classic: Constructor injection does not work in Rest Endpoints #39138

Open nimo23 opened 8 months ago

nimo23 commented 8 months ago

Describe the bug

I have this Rest endpoint:

import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.validation.Validator;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.sse.Sse;
import lombok.extern.jbosslog.JBossLog;

@Path("/")
@Singleton
@JBossLog
public class ConstructorInjectionResource {

    private final Sse sse;
    private final SecurityContext security;
    private final Validator validator;

    @Inject
    public ConstructorInjectionResource(@Context Sse sse, SecurityContext security, Validator validator) {
        log.info("CDI Constructor called");
        this.sse = sse;
        this.security = security;
        this.validator = validator;
        log.infov("this.sse = {0}", this.sse.getClass());
        log.infov("this.security = {0}", this.security.getClass());
        log.infov("this.validator = {0}", this.validator.getClass());
    }

    @PostConstruct
    public void postConstruct() {
        log.infov("@PostConstruct called: {0}", this.getClass().getSimpleName());
        log.infov("this.sse = {0}", this.sse.getClass());
    }

    @GET
    @Path("/hello1")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello1() {
        return "hello1";
    }

    @GET
    @Path("/hello2")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello2() {
        // Check that all fields are injected correctly through constructor injection:
        log.infov("this.sse = {0}", this.sse.getClass());
        log.infov("this.security = {0}", this.security.getClass());
        log.infov("this.validator = {0}", this.validator.getClass());
        return "hello2";
    }

}

It compiles without errors. And when doing localhost:8080/hello1 it prints "hello1". However, when going localhost:8080/hello2, then it throws a NullPointerException:

2024-03-03 13:02:02,575 ERROR [io.und.req.io] (executor-thread-2) Exception handling request 0efe619a-ccc2-4031-8d17-5c8555ea55ce-1 to /api/hello2: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException: Cannot invoke "jakarta.ws.rs.sse.Sse.getClass()" because "this.sse" is null
    at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:107)
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:344)

The NullPointerException is thrown because this bean did not invoke constructor injection (but instead created this bean with a null-argument constructor generated by Quarkus). Secondly, the @PostConstruct method wasn't called either.

Expected behavior

Constructor injection (of @Singleton or @ApplicationScoped beans) should work and the @PostConstruct method should also be called.

Actual behavior

Constructor injection (of @Singleton or @ApplicationScoped beans) does not work and the @PostConstruct method is also not called.

How to Reproduce?

  1. compile the class above and run it
  2. look at the console (no logs defined within the constructor injection and @PostConstructmethod are called)
  3. go to localhost:8080/hello1 (it works)
  4. go to localhost:8080/hello2 (throws NPE)

Output of uname -a or ver

No response

Output of java -version

openjdk version "21.0.2" 2024-01-16 OpenJDK Runtime Environment (build 21.0.2+13-58) OpenJDK 64-Bit Server VM (build 21.0.2+13-58, mixed mode, sharing)

Quarkus version or git rev

3.8.1

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

Even if this class is annotated with @Singleton, I suppose the same issue will also happen with @ApplicationScoped beans.

rysurd commented 8 months ago

Hello ! I can have a look if no one is on this already.

nimo23 commented 8 months ago

Ok, this problem only occurs when using RESTEasy Classic.

codespearhead commented 2 months ago

Possible duplicate of https://github.com/quarkusio/quarkus/issues/27273 .

Try this answer.