Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructor Inject @Context Sse not work with CDI scope #5854

Open
hantsy opened this issue Feb 4, 2025 · 0 comments
Open

Constructor Inject @Context Sse not work with CDI scope #5854

hantsy opened this issue Feb 4, 2025 · 0 comments

Comments

@hantsy
Copy link

hantsy commented Feb 4, 2025

I have filed an issue on Glassfish, eclipse-ee4j/glassfish#25323 but no one responded to it. I am not sure if it is an issue of the spec implementer.

Environment Details

  • GlassFish Version (and build number): 8.0.0-M9
  • JDK version: 21
  • OS: Windows 10 Pro 64bit
  • Database: Built-in derby and Docker/Postgres

Problem Description

In my cargo tracker fork, I tried to add an SSE broadcast endpoint to HTTP client to track the cargo event.

When using constructor inject, I have tried both EJB @Singleton and CDI @Singletone/@applicationScoped, but all do not work. But Replace the constructor injection with field injection, and it worked.

@Singleton
// @ApplicationScoped
@Path("tracking")
public class RealtimeCargoTrackingSseService {
    private static final Logger LOGGER =
            Logger.getLogger(RealtimeCargoTrackingSseService.class.getName());
    private Sse sse;
    private SseBroadcaster sseBroadcaster;

    public RealtimeCargoTrackingSseService() {}

    public RealtimeCargoTrackingSseService(@Context Sse sse) {
        this.sse = sse;
        this.sseBroadcaster = sse.newBroadcaster();
        this.sseBroadcaster.onClose(
                sseEventSink -> {
                    try {
                        sseEventSink.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
        this.sseBroadcaster.onError(
                (sseEventSink, throwable) -> {
                    sseEventSink.send(sse.newEvent("error", throwable.getMessage()));
                    try {
                        sseEventSink.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
    }

    @GET
    @Produces(SERVER_SENT_EVENTS)
    public void register(@Context SseEventSink sink) {
        LOGGER.log(Level.INFO, "register sink: {0}", sink);
        this.sseBroadcaster.register(sink);
    }

    public void onCargoInspected(@Observes @CargoInspected Cargo cargo) {
        LOGGER.log(INFO, "observers cargo inspected event of cargo: {0}", cargo.getTrackingId());

        Writer writer = new StringWriter();
        try (JsonGenerator generator = Json.createGenerator(writer)) {
            generator
                    .writeStartObject()
                    .write("trackingId", cargo.getTrackingId().id())
                    .write("origin", cargo.getOrigin().getName())
                    .write("destination", cargo.getRouteSpecification().destination().getName())
                    .write("lastKnownLocation", cargo.getDelivery().lastKnownLocation().getName())
                    .write("transportStatus", cargo.getDelivery().transportStatus().name())
                    .writeEnd();
        }
        String jsonValue = writer.toString();
        LOGGER.log(INFO, "sending message to client: {0}", jsonValue);

        OutboundSseEvent event =
                sse.newEventBuilder()
                        .name("event")
                        .mediaType(APPLICATION_JSON_TYPE)
                        .data(jsonValue)
                        .build();
        LOGGER.log(INFO, "broadcast event: {0}", event);
        this.sseBroadcaster.broadcast(event);
    }
}

It failed due to the NullPionterException from this.sseBroadcaster and this.sse in the further methods(eg. register) being called when registering the SSE client connection.

Problem Reproducer

  1. git clone https://github.com/hantsy/cargotracker
  2. switch to ee11 branch.
  3. Run test mvn clean verify -P"arq-glassfish-managed" -D"it.test=RealtimeCargoTrackingSseServiceTest"
  4. Or run the application in Glassfish container.
    • docker compose up postgres
    • mvn clean package cargo:run -P"glassfish"
    • curl http://localhost:8080/cargo-tracker/rest/tracking

My SSE class is similar to the broadcaster example in the Jersey docs, https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/sse.html and I remember this pattern worked in before projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant