Meaning of bean discovery mode annotated in CDI 1.1
Asked Answered
U

3

36

I am migrating an application to Java EE 7 and would like to CDI 1.1. But I don't get the meaning of bean-discovery-mode="annotated". The CDI 1.1 specification is not very helpful. At least I have not found any useful paragraph. Did I miss it?

This example runs perfectly with bean-discovery-mode="all" and injects an instance of LoggingClass:

public class LoggingClass {
    public Logger logger = Logger.getLogger("ALOGGER");

}

@Test
public class MMLoggerProducerIT extends Arquillian {

    @Inject private LoggingClass lc;

}

But if I change from bean-discovery-mode="all" to bean-discovery-mode="annotated" the container is not able to inject an instance into the field lc.

How do I have to annotate LoggingClass to use bean-discovery-mode="annotated" correctly?

Untimely answered 19/8, 2013 at 9:22 Comment(2)
I'm only guessing, but I think '@Named' or ''@ManagedBean' would be candidates?Fogarty
@Mike_Braun Named will only expose a bean in EL context but won't give it a scope. ManagedBean is a JSF annotation, CDI engine will ignore it.Pali
M
44

As a practical matter, bean-discovery-mode="ALL" turns on scanning of all classes in an archive. This is called an "explicit archive".

Omitting beans.xml, or setting bean-discovery-mode="ANNOTATED", makes the archive an implicit archive. In this case, the container will scan for beans with annotated scope types.

This explains why LoggingClass isn't injected when you set bean-discovery-mode="ANNOTATED". As documented in the Java EE 7 Tutorial:

CDI can only manage and inject beans annotated with a scope type in an implicit archive.

Edit: so just to be absolutely clear, you need to add a scope type to LoggingClass. So something like this:

@SessionScoped
public class LoggingClass {
    public Logger logger = Logger.getLogger("ALOGGER");
}

In Java EE 7 and CDI 1.1, we removed the requirement to include the beans.xml deployment descriptor to turn on CDI for an archive, bringing CDI 1.1 in line with most other Java EE APIs where deployment descriptors are optional. It also removed the binary on/off nature of including beans.xml or not. You can control which files are scanned by the container with the settings in bean-discovery-mode.

See the JavaEE tutorial on packaging CDI applications here: http://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm#CACDCFDE

Melodics answered 19/8, 2013 at 21:33 Comment(3)
If there is no beans.xml, how are Interceptors and Decorators registered and ordered? Is there a way?Ounce
@nosuchnick Interceptors can be ordered via annotations using @Interceptors and @Priority, as described in section 54.2.5 here.Melodics
does it describe how to get @Produces working? Is there an annotation I have to put in on the Factory class?Exceeding
R
49

When using bean-discovery-mode="annotated" only classes with a bean defining annotation are discovered. All other classes are ignored. Any scope type is a bean defining annotation. If a scope type is declared on a bean class, then the bean class is said to have a bean defining annotation [spec]. The 1.1 spec is not completely clear here. Only classes with a @NormalScope scope or @Dependent pseudo scope are discovered, @javax.inject.Singleton and all other @Scope (pseudo) scopes are ignored.

Note that the definition of a "bean defining annotation" changed in CDI 1.2 and is now very well defined:

The set of bean defining annotations contains:

  • @ApplicationScoped, @SessionScoped, @ConversationScoped and @RequestScoped annotations,
  • all other normal scope types,
  • @Interceptor and @Decorator annotations,
  • all stereotype annotations (i.e. annotations annotated with @Stereotype), and the @Dependent scope annotation.
Rooks answered 20/3, 2015 at 13:41 Comment(0)
M
44

As a practical matter, bean-discovery-mode="ALL" turns on scanning of all classes in an archive. This is called an "explicit archive".

Omitting beans.xml, or setting bean-discovery-mode="ANNOTATED", makes the archive an implicit archive. In this case, the container will scan for beans with annotated scope types.

This explains why LoggingClass isn't injected when you set bean-discovery-mode="ANNOTATED". As documented in the Java EE 7 Tutorial:

CDI can only manage and inject beans annotated with a scope type in an implicit archive.

Edit: so just to be absolutely clear, you need to add a scope type to LoggingClass. So something like this:

@SessionScoped
public class LoggingClass {
    public Logger logger = Logger.getLogger("ALOGGER");
}

In Java EE 7 and CDI 1.1, we removed the requirement to include the beans.xml deployment descriptor to turn on CDI for an archive, bringing CDI 1.1 in line with most other Java EE APIs where deployment descriptors are optional. It also removed the binary on/off nature of including beans.xml or not. You can control which files are scanned by the container with the settings in bean-discovery-mode.

See the JavaEE tutorial on packaging CDI applications here: http://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm#CACDCFDE

Melodics answered 19/8, 2013 at 21:33 Comment(3)
If there is no beans.xml, how are Interceptors and Decorators registered and ordered? Is there a way?Ounce
@nosuchnick Interceptors can be ordered via annotations using @Interceptors and @Priority, as described in section 54.2.5 here.Melodics
does it describe how to get @Produces working? Is there an annotation I have to put in on the Factory class?Exceeding
O
1

I also agree with the answer form @rmuller. But I want to point out that there is still different behavior on application servers Payara and Wildfly. See the following example with a normal not scoped class but having a @EJB injection:

public class SomeClass  {
    @EJB
    MyService myService;

   ...
}

If you provide a beans.xml file with:

 .... version="1.2" bean-discovery-mode="annotated"....

Payara 4.1 will treat the class SomeClass NOT as a CDI bean and will NOT inject the service EJB. This is clear to me that it behaves as stated in the specification.

But Wildfly 10 treats the class as an CDI bean and injects the service EJB which is not expected. To get this working the beans.xml file should look like this:

 .... version="1.2" bean-discovery-mode="all"....

It's amazing that the two most common application servers are different here in behavior.

Opulence answered 14/3, 2018 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.