eclipse-ee4j / eclipse-ee4j/jersey

Constructor Inject @Context Sse not work with CDI scope

Open
#5,854 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
730
Forks
382
PR merge metrics
No merged PRs in 30d

Description

I have filed an issue on Glassfish, https://github.com/eclipse-ee4j/glassfish/issues/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.**

```java
@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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.