Honor CDI scope of @ServerEndpoint beans in CdiComponentProvider#962
Open
renatsaf wants to merge 1 commit into
Open
Honor CDI scope of @ServerEndpoint beans in CdiComponentProvider#962renatsaf wants to merge 1 commit into
renatsaf wants to merge 1 commit into
Conversation
CdiComponentProvider.create() always produced a fresh endpoint instance per WebSocket connection via InjectionTarget, ignoring the bean's CDI scope. For an @ApplicationScoped or @singleton @serverendpoint this meant the per-connection endpoint object differed from the contextual bean seen by CDI event observers and other injection points, so state set in a lifecycle callback (e.g. a Set<Session> populated in @onopen) was invisible to observers that broadcast to it. Resolve the managed bean for the endpoint class and, when it is normal-scoped (@ApplicationScoped, @SessionScoped, ...) or @singleton, return the shared contextual reference from BeanManager.getReference() so callbacks, injected collaborators and observers all act on the same instance. Dependent-scoped (and non-bean) endpoints keep the previous per-connection behavior and are still cleaned up in destroy(); shared references are intentionally not registered for per-connection destruction. Adds a regression test covering @ApplicationScoped, @singleton and @dependent endpoints. Fixes eclipse-ee4j#961 Signed-off-by: Renat R. Safiullin <renatsaf@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
CdiComponentProvider.create()always produces a fresh endpoint instance per WebSocket connection through anInjectionTarget, ignoring the bean's CDI scope. For a@ServerEndpointthat is also@ApplicationScoped(orjakarta.inject.@Singleton), the per-connection endpoint object is therefore a different instance than the contextual bean that CDI routes events and other injection points to.The practical symptom (reported downstream in glassfish#25316): an endpoint stores
Sessions in a shared collection in@OnOpen, but a@Observesbroadcaster injected elsewhere sees an empty collection — the observer runs on the contextual bean, the sessions live on a throwaway per-connection object. The same pattern with an EJB@Singletonworks, becauseisApplicable()returnsfalsefor EJB annotations andEjbComponentProviderresolves the single instance via JNDI.Fix
In
create(), resolve the managedBeanfor the endpoint class. When it is normal-scoped (@ApplicationScoped,@SessionScoped, …) or@Singleton, return the shared contextual reference fromBeanManager.getReference()so lifecycle callbacks, injected collaborators and event observers all operate on the same instance.@Dependent(and non-bean) endpoints keep the existing per-connectionInjectionTargetbehavior. Shared references are intentionally not registered incdiBeanToContext, so closing one connection does not tear down a bean still in use by others — the CDI container owns their lifecycle. Per-connection (dependent) instances are still cleaned up indestroy()exactly as before.Behavioral note
For a normal-scoped endpoint,
getReference()returns a CDI client proxy; Tyrus invokes the@OnOpen/@OnMessagecallbacks through it, which is the intended, spec-compliant behavior. This is a behavior change only for code that (incorrectly) relied on getting per-connection instances of a scoped endpoint;@Dependentis bug-for-bug unchanged.Tests
Adds
CdiComponentProviderTest(a lightweightProxy-based fakeBeanManager, no new test dependencies beyond JUnit) covering:@ApplicationScoped→ same shared instance across connections@Singleton(pseudo-scope) → same shared instance across connections@Dependent→ a new instance per connectionFixes #961