Trash Can
Trash Can

Reputation: 6814

CDI will not work with implicit @Dependent scope, unsatisfied injection point compile time error

The container is Glassfish 4.1

I am having a very weird issue with CDI right now. If I don't annotate my NumberGenerator services @Dependent, then I keep getting unsatisfied injection point error when I run the app. But if I explicitly annotate my NumberGenerator implementations, then everything will work. In one word, if I want dependency injection with the @Dependent which is the default scope, I must specify it explicitly.

 public interface NumberGenerator {
    String generateNumber();  
 }

The first implementation of NumberGenerator

import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;

@ThirteenDigits
@Dependent
public class IsbnGenerator implements NumberGenerator {

    @Inject
    private Logger logger;

    @Override
    public String generateNumber() {
        String isbn = "13-84356-" + Math.abs(new Random().nextInt());
        logger.log(Level.INFO, "Generated ISBN : {0}", isbn);
        return isbn;
    }

}

The second implementation of NumberGenerator

import java.util.Random;
import java.util.logging.Logger;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;

@EightDigits
@Dependent
public class IssnGenerator implements NumberGenerator {

    @Inject
    private Logger logger;

    @Override
    public String generateNumber() {
        String issn = "8-" + Math.abs(new Random().nextInt());
        logger.info("Generated ISSN : " + issn);
        return issn;
    }

}

This is where the NumberGenerator will be injected

import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.interceptor.Interceptors;


@Dependent
public class BookService {

    @Inject 
    @EightDigits
    private NumberGenerator numberGenerator;

    public Book createBook(String title, float price, String description) {
        Book book = new Book(title, price, description);
        book.setNumber(numberGenerator.generateNumber());
        return book;
    }

}

Finally, the BookService is injected into this JSF managed bean to create a Book instance.

import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;


@Named
@Dependent /* if I leave this out, then this bean will not display 
              the book instance properties on the JSF page, I just see
              a blank screen, but when I add this @Dependent annotation
              the JSF page displays the dummy content below.
           */
public class MyBean {

    @Inject
    private BookService bookService;

    public Book getBook() {
    return bookService.createBook("Dummy Title", 21.05f, "Dummy Description");
    }

}

As you can see, I have to use @Dependent for the default scope every time I want DI. Right now, I am injecting the IssnGenerator with the qualifier @EightDigits into the BookService class, and if I remove the @Dependent from the IssnGenerator, I receive this compile error.

 Unsatisfied dependencies for type NumberGenerator with qualifiers @EightDigits at injection point [BackedAnnotatedField] @Inject @EightDigits private BookService.numberGenerator

Thank you for any suggestion.

Upvotes: 2

Views: 1598

Answers (1)

Benjamin
Benjamin

Reputation: 1846

If you do not specify a META-INF/beans.xml file, which seems to be your case, you got an implicit bean archive (see CDI-1.1 §12.1).

In an implicit bean archive, only beans with a bean defining annotation will be discovered by the CDI engine.

Any scope is a bean defining annotation (see CDI-1.1 §2.5). That's why if you add a scope, like @Dependent, you bean gets discovered by CDI and you don't have the unsatisfied dependency error.

The fact that @Dependent is the default scope is not relevant here because without the any scope your beans is simply not discovered.

If you add a META-INF/beans.xml file with the bean-discovery-mode set to all, then you got an explicit bean archive, this means that all beans in your archive will be discovered and will have the @Dependent scope by default.

Upvotes: 5

Related Questions