eclipse / lsp4jakarta

Language Server for Jakarta EE
Eclipse Public License 2.0
33 stars 51 forks source link

Depedency Injection: Diagnostic for unsatisfied depedencies with `@Inject` #164

Open KidoVin01 opened 2 years ago

KidoVin01 commented 2 years ago

Unsatisfied and ambiguous dependencies

An unsatisfied dependency exists at an injection point when no bean is eligible for injection to the injection point

Which Java classes are managed beans?

A Java class is a managed bean if it meets all of the following conditions:

  • is not an inner class.
  • It is a non-abstract class, or is annotated @Decorator.
  • It does not implement jakarta.enterprise.inject.spi.Extension.
  • It is not annotated @Vetoed or in a package annotated @Vetoed.
  • It has an appropriate constructor - either:
  • the class has a constructor with no parameters, or
  • the class declares a constructor annotated @Inject. All Java classes that meet these conditions are managed beans and thus no special declaration is required to define a managed bean.

Dependency injection and lookup

When resolving a bean at an injection point, the container considers bean type, qualifiers and selected alternatives

Beans and Attributes

A bean comprises the following attributes:

  • A (nonempty) set of bean types
  • A (nonempty) set of qualifiers
  • A scope
  • Optionally, a bean name
  • A set of interceptor bindings
  • A bean implementation

Furthermore, a bean may or may not be an alternative.

Diagnostics

  1. Identify @Inject field/method/constructor
  2. Locate all the dependency classes that are qualified as a managed bean.
  3. If none of the dependency classes matches exactly the bean type, qualifiers and selected alternatives, deliver an diagnostic error at the injection point that no satisfying classes found
  4. If the matching dependency class has no implementations, deliver a diagnostic error that the bean has no implementation (example)

Note 1: Only one dependency class must match, else ambiguous error would be thrown #163 Note 2: Diagnostics involving identifying annotation existence might not be possible and depends on #159

Example

The following is a fault code snippet example with @Qualifier:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
public @interface GreetingQual {}
// "Missing" @Qualifier
@ApplicationScoped
public class Greeting {
   public String greet(String name) {
        return "GreetingA, " + name;
    }
}
@WebServlet(name = "diUnQual", urlPatterns = { "/diUnQual" })
public class GreetingServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Inject @GreetingQual
    private Greeting greeting;

    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        String greetingString = greeting.greet("Bob");

        res.setContentType("text/html;charset=UTF-8");
        res.getWriter().println(greetingString);
    }
}
[INFO] [ERROR   ] CWWKZ0004E: An exception occurred while starting the application demo-servlet. The exception message was: com.ibm.ws.container.service.state.StateChangeException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type Greeting with qualifiers @Named
[INFO]   at injection point [BackedAnnotatedField] @Inject @Named private io.openliberty.sample.jakarta.di.unsatisfied.name.GreetingServlet.greeting
[INFO]   at io.openliberty.sample.jakarta.di.unsatisfied.name.GreetingServlet.greeting(GreetingServlet.java:0)
[INFO] WELD-001475: The following beans match by type, but none have matching qualifiers:
[INFO]   - Managed Bean [class io.openliberty.sample.jakarta.di.unsatisfied.name.Greeting] with qualifiers [@Any @Default]


Related to #153

kathrynkodama commented 2 years ago

Can you provide an example of how this might look?

KidoVin01 commented 2 years ago

Provided some example code demonstrating the errors.