Uploaded image for project: 'CDI Specification Issues'
  1. CDI Specification Issues
  2. CDI-109

Invalid beans should not be injectable into extensions

    • Icon: Feature Request Feature Request
    • Resolution: Done
    • Icon: Minor Minor
    • 1.1.PRD
    • 1.0, 1.1.EDR
    • Portable Extensions
    • None

      Currently, you can inject beans that may not be ready yet into the extension's call back methods. As an example, I can inject something application scoped like this in to an extension, but it should really be throwing a definition exception (or similar):

      public void handleABD(@Observes AfterBeanDiscovery abd, MyApplicationScopedBean masb) {

      }

      Pete had noted that really the only safe thing to inject, other than the observed call back, is the bean manager.

            [CDI-109] Invalid beans should not be injectable into extensions

            Closing all resolved issues in CDI 1.x

            Antoine Sabot-Durand (Inactive) added a comment - Closing all resolved issues in CDI 1.x

            Issued a pull at https://github.com/jboss/cdi/pull/89 for this and CDI-245, which resolves the issue around "inject into service providers" which is was a mistake.

            I haven't allowed extensions to inject other beans at runtime, that seems overly complex. If an extension wants to do something at runtime, it should define a bean that does it. The bean can inject the extension to obtain any information it needs from container initialization.

            I've also left what happens when the container injects something other than the BeanManager into an observer method as undefined, as I think there is room for an implementation to innovate here. It also allows an implementation to allow this runtime, for example.

            Pete Muir (Inactive) added a comment - Issued a pull at https://github.com/jboss/cdi/pull/89 for this and CDI-245 , which resolves the issue around "inject into service providers" which is was a mistake. I haven't allowed extensions to inject other beans at runtime, that seems overly complex. If an extension wants to do something at runtime, it should define a bean that does it. The bean can inject the extension to obtain any information it needs from container initialization. I've also left what happens when the container injects something other than the BeanManager into an observer method as undefined, as I think there is room for an implementation to innovate here. It also allows an implementation to allow this runtime, for example.

            Also consider removing following bullet from 6.4.2. Destruction of objects with scope @Dependent:

            Additionally, the container must ensure that:

            • ...
            • all @Dependent scoped contextual instances injected into method parameters of an observer method of any container lifecycle event, as defined in Section 11.5, “Container lifecycle events”, is destroyed after all observers of the BeforeShutdown event complete,
            • ...

            Martin Kouba added a comment - Also consider removing following bullet from 6.4.2. Destruction of objects with scope @Dependent : Additionally, the container must ensure that: ... all @Dependent scoped contextual instances injected into method parameters of an observer method of any container lifecycle event, as defined in Section 11.5, “Container lifecycle events”, is destroyed after all observers of the BeforeShutdown event complete, ...

            Jozef Hartinger added a comment - - edited

            As discussed on the IRC channel, using events at bootstrap is the only way for extensions to cooperate in CDI 1.0. Although CDI 1.1 introduces alternative ways, existing extensions may rely on this.

            In order to make the following paragraph shorter, I need to define this:
            OMWIPDOE = an observer method with injection points defined on an extension

            The question remains if we should do something with OMWIPDOEs which may be invoked at bootstrap when the container is not possible to satisfy the injection points. One approach is to scan for OMWIPDOE upfront and issue a definition error. My opinion is that this is too restrictive since it disallows OMWIPDOEs to be used at runtime, which are currently allowed. IMHO, instead of adding further restrictions and validating upfront, the container should check this at event delivery. If an injection point of a OMWIPDOE cannot be satisfied and the container is in the bootstrap phase, it should recognize this as a definition error. As a result, we get the same guarantees (recognizing the problem at the deployment time) as with the upfront scanning while being less restrictive at the same time (OMWIPDOEs would work at runtime).

            Jozef Hartinger added a comment - - edited As discussed on the IRC channel, using events at bootstrap is the only way for extensions to cooperate in CDI 1.0. Although CDI 1.1 introduces alternative ways, existing extensions may rely on this. In order to make the following paragraph shorter, I need to define this: OMWIPDOE = an observer method with injection points defined on an extension The question remains if we should do something with OMWIPDOEs which may be invoked at bootstrap when the container is not possible to satisfy the injection points. One approach is to scan for OMWIPDOE upfront and issue a definition error. My opinion is that this is too restrictive since it disallows OMWIPDOEs to be used at runtime, which are currently allowed. IMHO, instead of adding further restrictions and validating upfront, the container should check this at event delivery. If an injection point of a OMWIPDOE cannot be satisfied and the container is in the bootstrap phase, it should recognize this as a definition error. As a result, we get the same guarantees (recognizing the problem at the deployment time) as with the upfront scanning while being less restrictive at the same time (OMWIPDOEs would work at runtime).

            I would prefer to disallow normal observers at bootstrap for now

            Pete Muir (Inactive) added a comment - I would prefer to disallow normal observers at bootstrap for now

            This requires further clarification.

            The spec currently says that:

            Service providers may have observer methods, which may observe any event, including any container lifecycle event, and
            obtain an injected BeanManager reference. If other beans are injected into service providers, non-portable behavior results.

            The first part clearly indicates, that it is the observer method who may obtain the BeanManager. However, the second part

            If other beans are injected into service providers

            suggests the service providers can receive other types of injection (e.g. field injection), which is not allowed by the specification.

            The other issue is with the normal observer methods (those not observing a container lifecycle event). Such observer methods can be defined on extension and we should guarantee that if invoked at runtime, they behave the same as observer methods defined on other beans (i.e. injecting any bean is allowed).

            Hopefully, this table illustrates the problem better:

            This table describes injection guarantee the container should provide for a given type of observer method defined on an Extension in a particular phase container lifecycle event observer method normal observer method
            container initialization BeanManager, injection of other beans non-portable BeanManager, injection of other beans non-portable
            runtime N/A any bean can be injected

            Jozef Hartinger added a comment - This requires further clarification. The spec currently says that: Service providers may have observer methods, which may observe any event, including any container lifecycle event, and obtain an injected BeanManager reference. If other beans are injected into service providers, non-portable behavior results. The first part clearly indicates, that it is the observer method who may obtain the BeanManager. However, the second part If other beans are injected into service providers suggests the service providers can receive other types of injection (e.g. field injection), which is not allowed by the specification. The other issue is with the normal observer methods (those not observing a container lifecycle event). Such observer methods can be defined on extension and we should guarantee that if invoked at runtime, they behave the same as observer methods defined on other beans (i.e. injecting any bean is allowed). Hopefully, this table illustrates the problem better: This table describes injection guarantee the container should provide for a given type of observer method defined on an Extension in a particular phase container lifecycle event observer method normal observer method container initialization BeanManager, injection of other beans non-portable BeanManager, injection of other beans non-portable runtime N/A any bean can be injected

            Noted that injecting other beans can lead to non-portable behavior, this effectively just clarifies the spec, and highlights that an impl may choose to error at this point.

            Pete Muir (Inactive) added a comment - Noted that injecting other beans can lead to non-portable behavior, this effectively just clarifies the spec, and highlights that an impl may choose to error at this point.

            We can go two ways here. Either make it nonportable to look up beans in extensions, or mandate it's not possible.

            Advantage of nonportable is that it allows containers to innovate here. Any thoughts?

            Pete Muir (Inactive) added a comment - We can go two ways here. Either make it nonportable to look up beans in extensions, or mandate it's not possible. Advantage of nonportable is that it allows containers to innovate here. Any thoughts?

            Mark Struberg (Inactive) added a comment - - edited

            11.5. "Container lifecycle events" defines that system events work like normal @Observes methods. For a normal @Observes method, you can have additional parameters which get injected by the container:

            void clearCaches(@Observes CredentialsChangedEvent cce, BeanManager bm, User usr)

            {...}

            In this example, the bm and usr instances will get injected by the container.

            See 10.4.2. "Declaring an observer method":
            "In addition to the event parameter, observer methods may declare additional parameters, which may declare qualifiers. These additional parameters are injection points."

            But for Extensions, the only beans which can get injected are actually the builtin ones which already got initialized (e.g. the BeanManager itself). All other custom class beans are just not yet available for injection at the time the container gets bootstrapped.

            Mark Struberg (Inactive) added a comment - - edited 11.5. "Container lifecycle events" defines that system events work like normal @Observes methods. For a normal @Observes method, you can have additional parameters which get injected by the container: void clearCaches(@Observes CredentialsChangedEvent cce, BeanManager bm, User usr) {...} In this example, the bm and usr instances will get injected by the container. See 10.4.2. "Declaring an observer method": "In addition to the event parameter, observer methods may declare additional parameters, which may declare qualifiers. These additional parameters are injection points." But for Extensions, the only beans which can get injected are actually the builtin ones which already got initialized (e.g. the BeanManager itself). All other custom class beans are just not yet available for injection at the time the container gets bootstrapped.

            Can we expand on this? I am not sure I understand. Is there some supporting document blog, email thread? This is not clear.

            Richard Hightower (Inactive) added a comment - Can we expand on this? I am not sure I understand. Is there some supporting document blog, email thread? This is not clear.

              pmuiratbleepbleep Pete Muir (Inactive)
              meetoblivion_jira John Ament (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: