eclipse-ee4j / eclipse-ee4j/tyrus

CdiComponentProvider ignores CDI scope: @ApplicationScoped/@Singleton @ServerEndpoint gets a new instance per connection

Open
#961 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
128
Forks
49
PR merge metrics
No merged PRs in 30d

Description

**Module:** `tyrus-container-glassfish-cdi` (`org.glassfish.tyrus.gf.cdi.CdiComponentProvider`), Tyrus 2.2.2.

**Problem:** `create(Class)` always instantiates a fresh object via `InjectionTarget.produce()` regardless of the bean's scope. For a normal-scoped or `@Singleton` CDI endpoint this means the endpoint instance Tyrus uses is **not** the CDI contextual instance. Any state set in `@OnOpen` lives on the per-connection object, while `@Observes`/injected collaborators see the (separate) contextual bean — so e.g. a session registry populated in `@OnOpen` is invisible to a CDI observer broadcasting messages. Reported downstream at https://github.com/eclipse-ee4j/glassfish/issues/25316.

Current code:

```java
@Override
public Object create(Class c) {
if (managerRetrieved) {
AnnotatedType annotatedType = beanManager.createAnnotatedType(c);
InjectionTargetFactory injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
InjectionTarget it = injectionTargetFactory.createInjectionTarget(null);
CreationalContext cc = beanManager.createCreationalContext(null);
T managedObject = (T) it.produce(cc); // fresh object, scope ignored
it.inject(managedObject, cc);
it.postConstruct(managedObject);
cdiBeanToContext.put(managedObject, new CdiInjectionContext(it, cc));
return managedObject;
} else {
return null;
}
}
```

**Expected:** when the endpoint class is a normal-scoped or singleton CDI bean, return its contextual reference so endpoint callbacks and CDI event delivery share one instance (matching how `EjbComponentProvider` returns the single EJB instance).

**Sketch:**

```java
Set> beans = beanManager.getBeans(c);
if (!beans.isEmpty()) {
Bean bean = beanManager.resolve(beans);
Class scope = bean.getScope();
if (scope == ApplicationScoped.class || scope == Singleton.class /* normal/singleton scopes */) {
CreationalContext cc = beanManager.createCreationalContext(bean);
return beanManager.getReference(bean, c, cc); // contextual instance
}
}
// else: existing InjectionTarget path for dependent/per-connection endpoints
```

Dependent-scoped endpoints should keep the current per-connection behavior, per the WebSocket spec default (one endpoint instance per connection).

**Repro:** https://github.com/hantsy/cargotracker (branch `ee11`), `mvn clean verify -P"arq-glassfish-managed" -D"it.test=RealtimeCargoTrackingServiceTest"`.

Contributor guide

Open the contributing guide

Research direction

Start in tyrus-container-glassfish-cdi, at org.glassfish.tyrus.gf.cdi.CdiComponentProvider.create(Class), and compare its behavior with the EJB provider. Run the reported Cargotracker command to reproduce the issue. Done means normal-scoped and singleton endpoints use the CDI contextual instance while dependent endpoints retain per-connection behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.