hk2
  1. hk2
  2. HK2-95

Provide HK2 injectable constructor selection algorithm that meets JSR299, JSR330 and JAX-RS requirements.

    Details

    • Type: New Feature New Feature
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: 2.1.*
    • Fix Version/s: 2.1.*
    • Component/s: None
    • Labels:
      None

      Description

      JAX-RS spec says:

      If more than one public constructor is suitable then an implementation MUST use the one with the most parameters. Choosing amongst suitable constructors with the same number of parameters is implementation specific, implementations SHOULD generate a warning about such ambiguity.

      JSR330 says:

      Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class.

      Proposed solution:

      • If @Inject-annotated constructor exists, use that one
        • if more @Inject-annotated constructors exist, fail
      • If there's no @Inject-annotated constructor, then:
        • find all other injectable constructors (including no-arg or default constructors) and select the one with most parameters
          • if there are more constructors with most parameters, select first one and log warning.

        Activity

        Hide
        jwells added a comment -

        Unfortunately section 3.1.3 of CDI specifies:

        If the managed bean does not have a constructor that takes no parameters, it must have a constructor annotated @Inject.
        No additional special annotations are required.

        Unfortunately, the CDI specification (JSR 299) and the JAX-RS specification seem to be at odds on this issue.

        I wonder if we need to make this about the constructor being public. Like, if there is a PUBLIC zero-arg constructor, we use it (which would satisfy 299) and if not then we use the PUBLIC constructor with the greatest number of arguments, which would kind of satisfy JAX-RS.

        Of course, we will then run into the situation where a class has two constructors:

        public class Foo {
        public Foo() {
        }

        public Foo(Bar bar) {
        }
        }

        The trouble is that now HK2 can't pick. It will either be CDI-style happy (pick the zero-arg constructor) or JAX-RS happy (pick the one-arg constructor). Do we need to add a field or something to the descriptor saying how it should resolve this conflict?

        Show
        jwells added a comment - Unfortunately section 3.1.3 of CDI specifies: If the managed bean does not have a constructor that takes no parameters, it must have a constructor annotated @Inject. No additional special annotations are required. Unfortunately, the CDI specification (JSR 299) and the JAX-RS specification seem to be at odds on this issue. I wonder if we need to make this about the constructor being public. Like, if there is a PUBLIC zero-arg constructor, we use it (which would satisfy 299) and if not then we use the PUBLIC constructor with the greatest number of arguments, which would kind of satisfy JAX-RS. Of course, we will then run into the situation where a class has two constructors: public class Foo { public Foo() { } public Foo(Bar bar) { } } The trouble is that now HK2 can't pick. It will either be CDI-style happy (pick the zero-arg constructor) or JAX-RS happy (pick the one-arg constructor). Do we need to add a field or something to the descriptor saying how it should resolve this conflict?
        Hide
        jwells added a comment -

        This has been fixed by adding a new service called "ClassAnalyzer" that allows descriptors to choose how to analyze a class for its constructors, initializer methods, fields to be injected, post-construct method and pre-destroy method.

        The default ClassAnalyzer chooses the 299 approach (prefers the zero-arg constructor). However, we have also supplied a "prefers the constructor with the most parameters" choice as well, which can be used by using the ServiceLocatorUtilities.addPreferLargestConstructorClassAnalyzer. To be clear, JAX-RS descriptors should therefor have a ClassAnalyzer name of ServiceLocatorUtilities.PREFER_LARGEST_CONSTRUCTOR. (The ClassAnalyzer name can be set on a Descriptor).

        Among other parts of the solution:

        The @Service annotation now also takes an "analyzer" field which allows descriptors to choose their analyzer with an annotation.

        We will update GlassFish to call the addPreferLargestConstructorClassAnalyzer so that it can be used.

        Show
        jwells added a comment - This has been fixed by adding a new service called "ClassAnalyzer" that allows descriptors to choose how to analyze a class for its constructors, initializer methods, fields to be injected, post-construct method and pre-destroy method. The default ClassAnalyzer chooses the 299 approach (prefers the zero-arg constructor). However, we have also supplied a "prefers the constructor with the most parameters" choice as well, which can be used by using the ServiceLocatorUtilities.addPreferLargestConstructorClassAnalyzer. To be clear, JAX-RS descriptors should therefor have a ClassAnalyzer name of ServiceLocatorUtilities.PREFER_LARGEST_CONSTRUCTOR. (The ClassAnalyzer name can be set on a Descriptor). Among other parts of the solution: The @Service annotation now also takes an "analyzer" field which allows descriptors to choose their analyzer with an annotation. We will update GlassFish to call the addPreferLargestConstructorClassAnalyzer so that it can be used.

          People

          • Assignee:
            jwells
            Reporter:
            Marek Potociar
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: