0

My problem differs from both WELD-001408 Unsatisfied dependencies when injecting EntityManager and WELD-001408 Unsatisfied dependencies. While those issues dealt with trying to inject a managed bean into a stateless EJB, I'm trying to do the reverse.

I'm getting an "Unsatisfied dependencies" when attempting to inject a @Stateless @Local interfaced bean into a web managed bean. I'm building an EAR with various EJB modules and a web module, running Glassfish 4 build 89 on JDK 8. Below are the details of the error and project config.

First, here is the error:

SEVERE:   Exception while loading the app
SEVERE:   Undeployment failed for context /platform-app
SEVERE:   Exception while loading the app : CDI deployment failure:WELD-001408 Unsatisfied dependencies for type [SessionSettingsBeanLocal] with qualifiers [@MyClient] at injection point [[BackedAnnotatedField] @Inject @MyClient private com.comp.jsf.dropdown.Settings.settingsBean]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [SessionSettingsBeanLocal] with qualifiers [@MyClient] at injection point [[BackedAnnotatedField] @Inject @MyClient private com.comp.jsf.dropdown.Settings.settingsBean]

Custom qualifier (in library project):

@Documented
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public @interface MyClient

EJB interface (in library project):

@Local
public interface SessionSettingsBeanLocal

EJB implmentation (in EJB module project):

@Stateless
@MyClient
public class SessionSettingsBean implements SessionSettingsBeanLocal

Managed bean (in web project - used for JSF):

@Named
@javax.faces.view.ViewScoped
public class Settings implements Serializable {
    @Inject
    @MyClient
    private SessionSettingsBeanLocal settingsBean;

Lastly, all of my beans.xml files (EJB modules, web) look like the following. The libraries, which contain the interface and qualifier, don't have a beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="annotated">
</beans>

The @Stateless EJB should register itself, but it's not found.

Community
  • 1
  • 1
John Manko
  • 1,828
  • 27
  • 51
  • Why are you mixing custom CDI qualifiers and EJB? – ra2085 Jul 16 '14 at 21:23
  • I've had no problem with this exact thing in GF 3.1. I use qualifiers because I have multiple beans implementing the same @Local interface. – John Manko Jul 17 '14 at 01:17
  • I don't think that's the way to go. You should be using EJB 3.0 disanbiguation by string, not a CDI Qualifier. – ra2085 Jul 17 '14 at 02:26
  • have a look here: http://antoniogoncalves.org/2011/04/07/injection-with-cdi-part-i/ – ra2085 Jul 17 '14 at 02:27
  • and here. Very nice examples for EJB 3.0 disambiguation: http://www.oracle.com/technetwork/articles/java/cdi-javaee-bien-225152.html – ra2085 Jul 17 '14 at 02:27
  • Also, have you tried using this "private SessionSettingsBeanLocal sessionSettingsBean"? (instead of settingsBean alone, remember @Named is a default qualifier) – ra2085 Jul 17 '14 at 02:31
  • The Oracle link that you provided recommends the way I'm doing, and Adam Bien provides an exmple: Qualifying a dependency with a string is not type-safe... The CDI specification (JSR-299) discourages the use of string-based dependency resolution... The recommended way to qualify and to configure the dependencies is to use typed annotations with optional attributes instead of plain strings. These annotations are called qualifiers. It’s a standard annotation marked with a @Qualifier annotation. – John Manko Jul 17 '14 at 14:58
  • The link doesn't provide an example of your JSR-299/JSR-330 combination. It just states a simmilarity between String injection types. – ra2085 Jul 17 '14 at 17:06
  • Adam Bien provides a combination example, injecting Qualified JSR-299 beans into an EJB bean (not the other way around) http://www.adam-bien.com/roller/abien/entry/simplest_possible_ejb_3_15 – ra2085 Jul 17 '14 at 17:07
  • Looking at the 299 spec, found an example for your combination, I'll update the answer that I posted a while ago. Let me know how it goes. – ra2085 Jul 17 '14 at 17:08
  • Thanks ra2085. I appreciate it. I posted a follow up comment below, which should help. I think the problem is packaging, but I need to figure out how JAR-packaged @Named/scoped beans (meant for WAR JSF usage) can inject EJB-packaged @Stateless beans. – John Manko Jul 17 '14 at 21:04

3 Answers3

1

Try to change the bean-discovery-mode from annotated to all

Marina
  • 11
  • 1
  • consider adding more details to your answer, so that its easier for other people to understand – Inder Jul 26 '18 at 13:04
0

CDI Qualifiers are only meant to be used on CDI beans. Granted, you can inject EJB dependencies, but don't mix CDI qualifiers.

Here's a nice workaround from Arjan Tijms if you want to use qualifiers. link

UPDATE:

The 299 spec does mention EJB integration. They provide an example with both 299 and EJB annotations, which means, that bean will be CDI and EJB injectable. Here's the sample:

@Stateful @SessionScoped @Model
public class Login {
@Inject Credentials credentials;
@Inject @Users EntityManager userDatabase;
...
private User user;
@Inject
void initQuery(@Users EntityManagerFactory emf) {
...
}
@TransactionAttribute(REQUIRES_NEW)
@RolesAllowed("guest")
public void login() {
...
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user!=null;
}
@RolesAllowed("user")
@Produces @LoggedIn User getCurrentUser() {
...
}
}

So you may need to assign a scope to your SessionSettingsBean.

Community
  • 1
  • 1
ra2085
  • 814
  • 4
  • 13
0

You basically have three options how to overcome this

Completely switch to CDI

Since CDI 1.1 you can also use transactions in your beans so if you are not using remote EJBs, MDBs or anything else EJB specific, this would be way to go.

Produce EJB with Qualifier by another EJB

@Stateless
public class EJBProducer {

    @EJB
    private SessionSettingsBeanLocal settingsBean;

    @Produces 
    @MyClient
    public SessionSettingsBeanLocal getSettingsBean() {
        return settingsBean;
    }

}

Note tha this class has to be in WAR module. Now you can inject this EJB normally to CDI beans by its qualifier.

Distinguish EJB beans by their JNDI name

@Stateless
public class SessionSettingsBean implements SessionSettingsBeanLocal {}

Than just inject it to class like

@EJB(name = "SessionSettingsBean") 
private SessionSettingsBeanLocal bean; 

This way you can avoid CDI whatsoever.

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
  • I'm not using the `@EJB` injection annotation. I'm using CDI's `@Inject`, as recommended by many EE devs. even Gavin King: http://www.seamframework.org/107780.lace – John Manko Jul 17 '14 at 15:03
  • Sure, I would go for number one or two if I were you but I guess you should know about all options. – Petr Mensik Jul 17 '14 at 16:26
  • Well, I think it may have been a mistake on my part, but I'm unclear when injection is acceptable. The named bean (`Settings`) that has an EJB (`SessionSettingsBeanLocal`) injection point is actually in a JAR. Now, those `@Named @javax.faces.view.ViewScoped` beans (ie, managed beans for JSF) can be injected in both WAR and JAR beans, but the EJBs registered from an EJB package are not visible to the JAR. If I convert the JAR package to an EJB, then my Stateless EJBs are injected, but then injection of `@Named @javax.faces.view.ViewScoped` beans to other beans within the same package fails. – John Manko Jul 17 '14 at 20:59