• Icon: Bug Bug
    • Resolution: Obsolete
    • Icon: Minor Minor
    • 2.1 (Discussion)
    • None
    • Beans
    • None

      currently Bean#getBeanClass() is defined to return the class of the bean it produces but has one important exception: in case of a producer method or field it must return the class of the owner bean of this method or field.

      Imo this only causes troubles and doesn't add any benefit.

      • At the time when 'using' the Bean (create and destroy) we always ONLY need the type which is to be created.
      • At the time we create interceptors we ONLY need the type which is to be created;
      • At the time we create the normalscoping proxies we ONLY need the type which is to be created;

      In fact the only time we need the ownerBean is when scanning the methods and fields in it. And for creating we really need the owner-Bean and not it's bean-class!

      In OWB we worked around this by having our own method getReturnType() which consistently returns the type which gets created.

            [CDI-456] fix Bean#getBeanClass() definition

            The CDI project is part ofJakarta and uses GitHub issues as it's issue tracking system.
            Therefore, all issues in CDI JIRA project are being bulk-closed as described in this GitHub issue.

            If you feel like this particular issue deserves ongoing discussion, investigation or fixes in CDI/CDI TCK, please create a new issue under GitHub repository and include a link to this JIRA.

            For specification related question/issues, please use - https://github.com/eclipse-ee4j/cdi/issues
            For CDI TCK related questions/issues, please use - https://github.com/eclipse-ee4j/cdi-tck/issues

            Matฤ›j Novotnรฝ added a comment - The CDI project is part ofJakarta and uses GitHub issues as it's issue tracking system. Therefore, all issues in CDI JIRA project are being bulk-closed as described in this GitHub issue . If you feel like this particular issue deserves ongoing discussion, investigation or fixes in CDI/CDI TCK, please create a new issue under GitHub repository and include a link to this JIRA. For specification related question/issues, please use - https://github.com/eclipse-ee4j/cdi/issues For CDI TCK related questions/issues, please use - https://github.com/eclipse-ee4j/cdi-tck/issues

            +1

            โ€“
            Anatole Tresch
            Java Lead Engineer, JSR Spec Lead
            Glรคrnischweg 10
            CH - 8620 Wetzikon

            Switzerland, Europe Zurich, GMT+1
            Twitter: @atsticks
            *Blogs: **http://javaremarkables.blogspot.ch/
            <http://javaremarkables.blogspot.ch/>*

            Google: atsticksMobile +41-76 344 62 79

            Anatole Tresch (Inactive) added a comment - +1 โ€“ Anatole Tresch Java Lead Engineer, JSR Spec Lead Glรคrnischweg 10 CH - 8620 Wetzikon Switzerland, Europe Zurich, GMT+1 Twitter: @atsticks *Blogs: ** http://javaremarkables.blogspot.ch/ < http://javaremarkables.blogspot.ch/ >* Google: atsticksMobile +41-76 344 62 79

            antoinesabot-durand globally agree, I think producer (method/field) should also get a specific issue to make explicit that's a container thing (or allow providing new API to user to create some). This can make sense actually to allow to create programmatically producers

            Romain Manni-Bucau (Inactive) added a comment - antoinesabot-durand globally agree, I think producer (method/field) should also get a specific issue to make explicit that's a container thing (or allow providing new API to user to create some). This can make sense actually to allow to create programmatically producers

            We all know there are issues with the Java EE module architecture. This has to be fix at Java EE level and CDI spec will have to follow not the other way around.
            Now, regarding this ticket I think Jozef explained more than once why Bean#getBeanClass() should behave this way. Yet I understand the need to get the exact type of a given bean instances. So IMO we should split this ticket in 2 :

            1. Clarify the javadoc and spec description of Bean#getBeanClass() to avoid confusion
            2. Add a new method to Bean returning the exact type of the bean instances. something like Bean#getInstanceClass()

            Antoine Sabot-Durand (Inactive) added a comment - We all know there are issues with the Java EE module architecture. This has to be fix at Java EE level and CDI spec will have to follow not the other way around. Now, regarding this ticket I think Jozef explained more than once why Bean#getBeanClass() should behave this way. Yet I understand the need to get the exact type of a given bean instances. So IMO we should split this ticket in 2 : Clarify the javadoc and spec description of Bean#getBeanClass() to avoid confusion Add a new method to Bean returning the exact type of the bean instances. something like Bean#getInstanceClass()

            jozef, how should that work? The 3 beans are different but have the same beanClass(). So how should this get implemented?

            Look at the example again. They do not have the same bean class. If they had the same bean class then that would be a bug.

            So what? Where in this sentence does it state that the 'bean class of the bean' cannot be null? It neither does define what the 'bean class of the bean' is used for by the container.
            oh fine, but this is not about Alternatives!
            Show me one single line where you read that getBeanClass() must not be null for any custom bean.
            This is just missing from the spec and we should clarify what should happen in this case.

            Very weird logic you are using here. BeanManager.fireEvent() does not specify that you cannot pass null, either. Yet, we can probably agree that calling BeanManager.fireEvent(null) is a stupid thing to do. Here, the spec clearly says that for a custom bean, CDI will call getBeanClass() to infer several pieces of information about the bean yet you feel that returning null is alright?

            Jozef Hartinger added a comment - jozef, how should that work? The 3 beans are different but have the same beanClass(). So how should this get implemented? Look at the example again. They do not have the same bean class. If they had the same bean class then that would be a bug. So what? Where in this sentence does it state that the 'bean class of the bean' cannot be null? It neither does define what the 'bean class of the bean' is used for by the container. oh fine, but this is not about Alternatives! Show me one single line where you read that getBeanClass() must not be null for any custom bean. This is just missing from the spec and we should clarify what should happen in this case. Very weird logic you are using here. BeanManager.fireEvent() does not specify that you cannot pass null, either. Yet, we can probably agree that calling BeanManager.fireEvent(null) is a stupid thing to do. Here, the spec clearly says that for a custom bean, CDI will call getBeanClass() to infer several pieces of information about the bean yet you feel that returning null is alright?

            jozef, how should that work? The 3 beans are different but have the same beanClass(). So how should this get implemented?

            let's look at what you quoted.

            5.1.4
            For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls getBeanClass() to determine the bean class of the bean

            So what? Where in this sentence does it state that the 'bean class of the bean' cannot be null? It neither does define what the 'bean class of the bean' is used for by the container.

            5.1.1.2
            For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls .. getBeanClass() and getStereotypes() to determine whether an alternative is selected in a certain bean archive.

            oh fine, but this is not about Alternatives!

            Show me one single line where you read that getBeanClass() must not be null for any custom bean.
            This is just missing from the spec and we should clarify what should happen in this case.

            Mark Struberg (Inactive) added a comment - jozef, how should that work? The 3 beans are different but have the same beanClass(). So how should this get implemented? let's look at what you quoted. 5.1.4 For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls getBeanClass() to determine the bean class of the bean So what? Where in this sentence does it state that the 'bean class of the bean' cannot be null? It neither does define what the 'bean class of the bean' is used for by the container. 5.1.1.2 For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls .. getBeanClass() and getStereotypes() to determine whether an alternative is selected in a certain bean archive. oh fine, but this is not about Alternatives! Show me one single line where you read that getBeanClass() must not be null for any custom bean. This is just missing from the spec and we should clarify what should happen in this case.

            I think main issue today regarding it is the javadoc doesn't state what you get when. So basically you don't know what you get. IMHO this thing should be well defined and not rely on a "hack"

            getBeanClass still makes sense for proxying IMHO

            Romain Manni-Bucau (Inactive) added a comment - I think main issue today regarding it is the javadoc doesn't state what you get when. So basically you don't know what you get. IMHO this thing should be well defined and not rely on a "hack" getBeanClass still makes sense for proxying IMHO

            The whole modularity in EAR otoh requires that JavaEE FINALLY properly defines the default isolation (EAR as 1 classloader + each WAR as child ClassLoader, etc) as standard. If the EE platform doesn't have a proper modularity specification we have a floating target and cannot define how CDI should handle it neither.

            Let's suppose for a moment that Java EE finally properly defined its module architecture. Now, how should we define CDI modularity? Should it follow the underlying module architecture or go against it? I think we can agree that we should not define a different architecture but rather follow the underlying one. But wait... that's what CDI already does by using class accessibility to infer bean accessibility

            Jozef Hartinger added a comment - The whole modularity in EAR otoh requires that JavaEE FINALLY properly defines the default isolation (EAR as 1 classloader + each WAR as child ClassLoader, etc) as standard. If the EE platform doesn't have a proper modularity specification we have a floating target and cannot define how CDI should handle it neither. Let's suppose for a moment that Java EE finally properly defined its module architecture. Now, how should we define CDI modularity? Should it follow the underlying module architecture or go against it? I think we can agree that we should not define a different architecture but rather follow the underlying one. But wait... that's what CDI already does by using class accessibility to infer bean accessibility

            Bean#getBeanClass() is only defined for 'Managed Beans' at the moment. That means it is only defined for classes which get scanned at boot time. It is not defined for anything you do via Extensions.

            The Javadoc defines Bean#getBeanClass() for managed beans, session beans, producer methods and producer fields. Not just managed beans. In addition, although Bean#getBeanClass() is not explicitly defined for custom beans, the expected behavior can be implied from sections 5.1, 5.1.1.2 and 5.1.4. The behavior for custom beans should be defined more explicitly as currently it needs to be implied and is not immediately obvious.

            it wont work for 3 custom Bean<T> which are differently configured for each of the 3 WARs

            See my example above. It works there.

            Especially since getBeanClass() might return null if you strictly follow the spec wording.

            For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls getBeanClass() to determine the bean class of the bean

            Since 'bean class' is used in 5.1.4. to determine if the bean is available for injection then returning null from getBeanClass is arguably a definition error.

            Jozef Hartinger added a comment - Bean#getBeanClass() is only defined for 'Managed Beans' at the moment. That means it is only defined for classes which get scanned at boot time. It is not defined for anything you do via Extensions. The Javadoc defines Bean#getBeanClass() for managed beans, session beans, producer methods and producer fields . Not just managed beans. In addition, although Bean#getBeanClass() is not explicitly defined for custom beans, the expected behavior can be implied from sections 5.1, 5.1.1.2 and 5.1.4. The behavior for custom beans should be defined more explicitly as currently it needs to be implied and is not immediately obvious. it wont work for 3 custom Bean<T> which are differently configured for each of the 3 WARs See my example above. It works there. Especially since getBeanClass() might return null if you strictly follow the spec wording. For a custom implementation of the Bean interface defined in Section 11.1, โ€œThe Bean interfaceโ€, the container calls getBeanClass() to determine the bean class of the bean Since 'bean class' is used in 5.1.4. to determine if the bean is available for injection then returning null from getBeanClass is arguably a definition error.

            to also add what we discussed on IRC on friday:

            Bean#getBeanClass() is only defined for 'Managed Beans' at the moment. That means it is only defined for classes which get scanned at boot time. It is not defined for anything you do via Extensions.

            regarding the modularity discussion: yes, using getBeanClass() for that would work for ManagedBeans which get scanned by the container, but again: it wont work for 3 custom Bean<T> which are differently configured for each of the 3 WARs. Especially since getBeanClass() might return null if you strictly follow the spec wording.

            So I think we need to
            a.) clarify what getBeanClass() shall return for Bean<T> added via Extensions
            b.) how modularity works for synthetic beans.

            The whole modularity in EAR otoh requires that JavaEE FINALLY properly defines the default isolation (EAR as 1 classloader + each WAR as child ClassLoader, etc) as standard. If the EE platform doesn't have a proper modularity specification we have a floating target and cannot define how CDI should handle it neither.

            Mark Struberg (Inactive) added a comment - to also add what we discussed on IRC on friday: Bean#getBeanClass() is only defined for 'Managed Beans' at the moment. That means it is only defined for classes which get scanned at boot time. It is not defined for anything you do via Extensions. regarding the modularity discussion: yes, using getBeanClass() for that would work for ManagedBeans which get scanned by the container, but again: it wont work for 3 custom Bean<T> which are differently configured for each of the 3 WARs. Especially since getBeanClass() might return null if you strictly follow the spec wording. So I think we need to a.) clarify what getBeanClass() shall return for Bean<T> added via Extensions b.) how modularity works for synthetic beans. The whole modularity in EAR otoh requires that JavaEE FINALLY properly defines the default isolation (EAR as 1 classloader + each WAR as child ClassLoader, etc) as standard. If the EE platform doesn't have a proper modularity specification we have a floating target and cannot define how CDI should handle it neither.

            Enough to define it well next tim, no?

            We cannot just redefine the method's behavior (as otherwise we break other things).
            We can:
            1) define a new better mechanism for this, or
            2) redefine the method behavior and the related parts of the spec while retaining backward compatibility (hard or perhaps not possible at all), or
            3) leave it as it is

            Jozef Hartinger added a comment - Enough to define it well next tim, no? We cannot just redefine the method's behavior (as otherwise we break other things). We can: 1) define a new better mechanism for this, or 2) redefine the method behavior and the related parts of the spec while retaining backward compatibility (hard or perhaps not possible at all), or 3) leave it as it is

            Not sure I get

            • cannot be redefined to simply return the bean type - besides breaking backward compatibility this would also break how other parts of CDI work

            Enough to define it well next tim, no?

            Romain Manni-Bucau (Inactive) added a comment - Not sure I get cannot be redefined to simply return the bean type - besides breaking backward compatibility this would also break how other parts of CDI work Enough to define it well next tim, no?

            Anatole, you are completely right. But why does it work this way?

            The behavior is driven by the following statement in the specification:

            A bean is available for injection in a certain module if the bean class is required to be accessible to classes in the module, according to the class
            accessibility requirements of the module architecture.

            Let's expand your example a bit to demonstrate this. Let's say that your producers are called MyProducer1, MyProducer2, MyProducer3 and are packaged in war1, war2 and war3, respectively.

            Now, let's inject MyBean in war1. MyProducer1.create() is the first candidate. Since the bean class of MyProducer1.create() is MyProducer1 and since this class is accessible within war1, we can use MyProducer1.create() to create a MyBean instance. For MyProducer2 and MyProducer3 this is not the case as we assume wars are isolated. This is expected and in line with your conclusion.

            Notice that although MyProducer1.create() produces MyBean instances, MyProducer1 is its bean class. If we made MyBean the bean class of MyProducer1, MyProducer2 and MyProducer3 (as this ticket proposes), all three producer methods would be available for injection in any of the wars, which is obviously not desired! The aforementioned CDI accessibility rule determines the accessibility of the bean by its bean class and therefore we cannot pronounce the return type of a producer method as its bean class.




            Custom Bean<T> implementations are very similar. Image now that instead of using MyProducer classes, our example uses MyBeanProvider classes defined as:

            public class MyBeanProvider implements Bean<MyBean> {
            
               public T create(CreationalContext<T> creationalContext) {
                  return new MyBean();
               }
            
            ...
            }
            

            Again, we have MyBeanProvider1, MyBeanProvider2, MyBeanProvider3 in war1, war2, war3, respectively. Each bean provider is registered by an extension.

            What should MyBeanProvider1.getBeanClass() return? Let's assume it returns MyBeanProvider1.class. Once we apply the accessibility rule of CDI we can see that each war again gets its respective bean producing MyBean instances and that the bean isolation follows classloader isolation. This is again the expected behavior, matching Anatole's example.

            If we however follow the "simplification proposed by this ticket" and return MyBean.class from MyBeanProvider1.getBeanClass() then, not unlike with producers, MyBeanProvider1 will be visible from all the three wars, which is not desired. This would be because MyBean.class is accessible from all the three wars. The CDI accessibility rule determines the accessibility of the bean by its bean class and therefore we cannot just blindly return a bean type from Bean.getBeanClass().

            Hope this makes it clearer that Bean.getBeanClass()

            • exists for a reason
            • it is not a shortcut to bean types and there is often absolutely no relation between Bean<T>.getTypes() and Bean<T>.getBeanClass()
            • although probably not the ideal way of addressing modularity and isolation (and subject to improvement in CDI 2.0), it works
            • cannot be redefined to simply return the bean type - besides breaking backward compatibility this would also break how other parts of CDI work

            Jozef Hartinger added a comment - Anatole, you are completely right. But why does it work this way? The behavior is driven by the following statement in the specification: A bean is available for injection in a certain module if the bean class is required to be accessible to classes in the module , according to the class accessibility requirements of the module architecture. Let's expand your example a bit to demonstrate this. Let's say that your producers are called MyProducer1 , MyProducer2 , MyProducer3 and are packaged in war1, war2 and war3, respectively. Now, let's inject MyBean in war1. MyProducer1.create() is the first candidate. Since the bean class of MyProducer1.create() is MyProducer1 and since this class is accessible within war1, we can use MyProducer1.create() to create a MyBean instance. For MyProducer2 and MyProducer3 this is not the case as we assume wars are isolated. This is expected and in line with your conclusion. Notice that although MyProducer1.create() produces MyBean instances, MyProducer1 is its bean class. If we made MyBean the bean class of MyProducer1 , MyProducer2 and MyProducer3 ( as this ticket proposes ), all three producer methods would be available for injection in any of the wars, which is obviously not desired! The aforementioned CDI accessibility rule determines the accessibility of the bean by its bean class and therefore we cannot pronounce the return type of a producer method as its bean class. Custom Bean<T> implementations are very similar. Image now that instead of using MyProducer classes, our example uses MyBeanProvider classes defined as: public class MyBeanProvider implements Bean<MyBean> { public T create(CreationalContext<T> creationalContext) { return new MyBean(); } ... } Again, we have MyBeanProvider1 , MyBeanProvider2 , MyBeanProvider3 in war1, war2, war3, respectively. Each bean provider is registered by an extension. What should MyBeanProvider1.getBeanClass() return? Let's assume it returns MyBeanProvider1.class . Once we apply the accessibility rule of CDI we can see that each war again gets its respective bean producing MyBean instances and that the bean isolation follows classloader isolation. This is again the expected behavior, matching Anatole's example. If we however follow the "simplification proposed by this ticket" and return MyBean.class from MyBeanProvider1.getBeanClass() then, not unlike with producers, MyBeanProvider1 will be visible from all the three wars, which is not desired. This would be because MyBean.class is accessible from all the three wars. The CDI accessibility rule determines the accessibility of the bean by its bean class and therefore we cannot just blindly return a bean type from Bean.getBeanClass() . Hope this makes it clearer that Bean.getBeanClass() exists for a reason it is not a shortcut to bean types and there is often absolutely no relation between Bean<T>.getTypes() and Bean<T>.getBeanClass() although probably not the ideal way of addressing modularity and isolation (and subject to improvement in CDI 2.0), it works cannot be redefined to simply return the bean type - besides breaking backward compatibility this would also break how other parts of CDI work

            Jozef, imagine the following

            public class MyProducer{
            @Produces @ApplicationScoped
              public MyBean create(){ return new MyBean(); }
            }
            

            The MyBean class is declared in the ear, as follows:

            public final class MyBean{
                 public final String CONTEXT = Thread.currentThread().getContextClassLoader().toString();
            }
            

            Now you have 3 wars, the class instance for MyBean will be the same for all three wars, since it is loaded from the ear classloader (but also visible to the war classloader).
            Nevertheless, since the MyProducer producer class is defined on war level, you get three different instances, each with a different CONTEXT...

            Anatole Tresch (Inactive) added a comment - Jozef, imagine the following public class MyProducer{ @Produces @ApplicationScoped public MyBean create(){ return new MyBean(); } } The MyBean class is declared in the ear , as follows: public final class MyBean{ public final String CONTEXT = Thread.currentThread().getContextClassLoader().toString(); } Now you have 3 wars, the class instance for MyBean will be the same for all three wars, since it is loaded from the ear classloader (but also visible to the war classloader). Nevertheless, since the MyProducer producer class is defined on war level , you get three different instances, each with a different CONTEXT ...

            Jozef NO IT DOES NOT!

            beanclass -> Bean<T> is NOT 1:1 if you register different Bean<T> in each of the 3 WAR files.

            Mark Struberg (Inactive) added a comment - Jozef NO IT DOES NOT! beanclass -> Bean<T> is NOT 1:1 if you register different Bean<T> in each of the 3 WAR files.

            There are situations where the type of the class is not enough to determine the module.

            As long as you use the right class as the bean class, which often is not the bean type, this works for producers and custom beans.

            Jozef Hartinger added a comment - There are situations where the type of the class is not enough to determine the module. As long as you use the right class as the bean class, which often is not the bean type, this works for producers and custom beans.

            rhn-engineering-jharting you still get me wrong. There are situations where the type of the class is not enough to determine the module. It does work for producer methods which are NOT modified/created via Extensions, but that's all. And for those (producers are ONLY internal beans) the container has MUCH better ways to detect the module.

            Which means it is absolutely useless and just makes it impossible to properly do things like e.g. ProcessProducer etc....

            Mark Struberg (Inactive) added a comment - rhn-engineering-jharting you still get me wrong. There are situations where the type of the class is not enough to determine the module. It does work for producer methods which are NOT modified/created via Extensions, but that's all. And for those (producers are ONLY internal beans) the container has MUCH better ways to detect the module. Which means it is absolutely useless and just makes it impossible to properly do things like e.g. ProcessProducer etc....

            But just using a Class which can be used in tons of different Beans is not.

            Exactly. If bean type and bean class are the same thing (as this ticket proposes) accesibility resolution won't work well. That's why it is important for producers and often custom beans to distinguish between the type of the bean and the class that defines it!

            Jozef Hartinger added a comment - But just using a Class which can be used in tons of different Beans is not. Exactly. If bean type and bean class are the same thing (as this ticket proposes) accesibility resolution won't work well. That's why it is important for producers and often custom beans to distinguish between the type of the bean and the class that defines it!

            Using beanClass and classloader is not portable at all and even if EE containers can surely deal with it, in SE and OSGi worlds it will be very fragile.

            No matter what environment you are running, if you have class A and class B in Java you can always tell if A's ClassLoader can see B or not. No matter if it's OSGi, an EE container that does or does not isolate modules, a plain flat SE classpath or something completely different, you can always determine this.

            What CDI should do is to behave the same and make A injectable to B as long as A is visible from B or in other words if you can do new A() within B. That is the only sane way to define accesibility in CDI - to follow ClassLoader accesibility.

            Jozef Hartinger added a comment - Using beanClass and classloader is not portable at all and even if EE containers can surely deal with it, in SE and OSGi worlds it will be very fragile. No matter what environment you are running, if you have class A and class B in Java you can always tell if A's ClassLoader can see B or not. No matter if it's OSGi, an EE container that does or does not isolate modules, a plain flat SE classpath or something completely different, you can always determine this. What CDI should do is to behave the same and make A injectable to B as long as A is visible from B or in other words if you can do new A() within B. That is the only sane way to define accesibility in CDI - to follow ClassLoader accesibility.

            mkouba@redhat.com yes, 3 Extensions - 1 in each of the WARs - add 3 different Bean<T> which produce the same Class, but different content.

            The container must not use the class to detect in which part of the application the Bean is valid and in which not. There must be other mechanisms. Each of the WARs could use a different Extension instance for example and store the created/parsed/whatever Beans in a different location. THAT would be modular. But just using a Class which can be used in tons of different Beans is not.

            Mark Struberg (Inactive) added a comment - mkouba@redhat.com yes, 3 Extensions - 1 in each of the WARs - add 3 different Bean<T> which produce the same Class, but different content. The container must not use the class to detect in which part of the application the Bean is valid and in which not. There must be other mechanisms. Each of the WARs could use a different Extension instance for example and store the created/parsed/whatever Beans in a different location. THAT would be modular. But just using a Class which can be used in tons of different Beans is not.

            more I think to it more I see an issue. If the goal is module visibility resolution then we should add a Bean#isVisible(Module) - with Module providing at least the ClassLoader, maybe a name from beans.xml like in ejb-jar.xml, the location?... Using beanClass and classloader is not portable at all and even if EE containers can surely deal with it, in SE and OSGi worlds it will be very fragile.

            I think this can be an interesting topic to complete scanning config which was recently introduced. This will be close to OSGi import/export control then.

            Romain Manni-Bucau (Inactive) added a comment - more I think to it more I see an issue. If the goal is module visibility resolution then we should add a Bean#isVisible(Module) - with Module providing at least the ClassLoader, maybe a name from beans.xml like in ejb-jar.xml, the location?... Using beanClass and classloader is not portable at all and even if EE containers can surely deal with it, in SE and OSGi worlds it will be very fragile. I think this can be an interesting topic to complete scanning config which was recently introduced. This will be close to OSGi import/export control then.

            The CDI container would do that. The container would not provide the bean if it's not visible to another module.

            In the end this means Bean#getBeanClass() is the class of the providing bean (either the class itself or the producer class).

            Introducing a Bean.getProxiableType() that consistently returns the type which gets created could be a possible solution to inspect the type of the resulting object. Other DI frameworks name it for example getObjectType().

            Mark Paluch (Inactive) added a comment - The CDI container would do that. The container would not provide the bean if it's not visible to another module. In the end this means Bean#getBeanClass() is the class of the providing bean (either the class itself or the producer class). Introducing a Bean.getProxiableType() that consistently returns the type which gets created could be a possible solution to inspect the type of the resulting object. Other DI frameworks name it for example getObjectType() .

            so you mean by testing the classloader from one class to the other? this is broken in OSGi where you often use proxy in create() but not in getBeanClass to allow this to work

            Romain Manni-Bucau (Inactive) added a comment - - edited so you mean by testing the classloader from one class to the other? this is broken in OSGi where you often use proxy in create() but not in getBeanClass to allow this to work

            You can rely on that always. No matter where bean1 and bean2 are packaged you know that bean1 can be injected into bean2 as long as bean2.getBeanClass() can see bean1.getBeanClass().

            I agree with you that this is by no means ideal and there are better ways to express this e.g. your getLocation() method.

            Jozef Hartinger added a comment - You can rely on that always. No matter where bean1 and bean2 are packaged you know that bean1 can be injected into bean2 as long as bean2.getBeanClass() can see bean1.getBeanClass(). I agree with you that this is by no means ideal and there are better ways to express this e.g. your getLocation() method.

            well my point is you can't rely on it generally so its usage shouldn't be this one. Maybe it just means we should have getProxiableType() and getLocation in Bean2<?> (next version)

            wdyt?

            Romain Manni-Bucau (Inactive) added a comment - well my point is you can't rely on it generally so its usage shouldn't be this one. Maybe it just means we should have getProxiableType() and getLocation in Bean2<?> (next version) wdyt?

            If you use beanclass and that the bean class is not in the app (in upper classloaders) then what do you do?

            That's a different question. If the bean class is in the app though then getBeanClass() can tell us whether this bean belongs to war1, war2, war3, shared library or somewhere else which is pretty important information.

            Jozef Hartinger added a comment - If you use beanclass and that the bean class is not in the app (in upper classloaders) then what do you do? That's a different question. If the bean class is in the app though then getBeanClass() can tell us whether this bean belongs to war1, war2, war3, shared library or somewhere else which is pretty important information.

            for wars it is mainly a 'flat' classloader so all beans are "shared" so nothing fancy to do?

            for extension yes but honestly not sure that's that important. If you use beanclass and that the bean class is not in the app (in upper classloaders) then what do you do?

            Romain Manni-Bucau (Inactive) added a comment - for wars it is mainly a 'flat' classloader so all beans are "shared" so nothing fancy to do? for extension yes but honestly not sure that's that important. If you use beanclass and that the bean class is not in the app (in upper classloaders) then what do you do?

            Jozef Hartinger added a comment - - edited

            You think it is here for modules?

            Not only for modules but yes. It's referenced quite a lot in Section 5.1. Modularity

            Well in a war no big deal

            How?

            in an ear the container does it since it deploys it

            How? You have an extension that registered a custom bean. What information do you use to infer where the bean belongs? The same module as the extension's? Some type from Bean.getTypes()? Or something else?

            Jozef Hartinger added a comment - - edited You think it is here for modules? Not only for modules but yes. It's referenced quite a lot in Section 5.1. Modularity Well in a war no big deal How? in an ear the container does it since it deploys it How? You have an extension that registered a custom bean. What information do you use to infer where the bean belongs? The same module as the extension's? Some type from Bean.getTypes()? Or something else?

            Well in a war no big deal, in an ear the container does it since it deploys it. If you 100% want to do it from the CDI container "alone" you just can't. Then you are right you can use bean class but it doesn't cover 100% of cases (most of them for sure). It doesn't change the main point: getBeanClass is not designed for it IMHO, no? You think it is here for modules?

            Romain Manni-Bucau (Inactive) added a comment - Well in a war no big deal, in an ear the container does it since it deploys it. If you 100% want to do it from the CDI container "alone" you just can't. Then you are right you can use bean class but it doesn't cover 100% of cases (most of them for sure). It doesn't change the main point: getBeanClass is not designed for it IMHO, no? You think it is here for modules?

            Can you elaborate more on how a CDI implementation should know which module a custom Bean<T> belongs to? I am not able to understand that from your reply.

            Jozef Hartinger added a comment - Can you elaborate more on how a CDI implementation should know which module a custom Bean<T> belongs to? I am not able to understand that from your reply.

            Classloading isolation can be restricted but it doesn't mean you don't inherit from other beans (typically in OSGi you can get proxies to solve it).

            In EE that's the same, nothing prevents it if you custom beans handle it correctly. In EE that's worse since the deployment is pretty clear (=hierarchic) so no need to test Class to know what should be done.

            Romain Manni-Bucau (Inactive) added a comment - Classloading isolation can be restricted but it doesn't mean you don't inherit from other beans (typically in OSGi you can get proxies to solve it). In EE that's the same, nothing prevents it if you custom beans handle it correctly. In EE that's worse since the deployment is pretty clear (=hierarchic) so no need to test Class to know what should be done.

            Class<?> is not enough to know from which module you are so it is not usable (OSGi or EE).

            Why not? And if not how otherwise should the CDI impl know which module the custom Bean<T> belongs to?

            Jozef Hartinger added a comment - Class<?> is not enough to know from which module you are so it is not usable (OSGi or EE). Why not? And if not how otherwise should the CDI impl know which module the custom Bean<T> belongs to?

            struberg What do you mean "WAR files add a Bean with the same class"? By means of a portable extension?

            Martin Kouba added a comment - struberg What do you mean "WAR files add a Bean with the same class"? By means of a portable extension?

            Class<?> is not enough to know from which module you are so it is not usable (OSGi or EE). I tend to be agree with Mark, beanClass can be the producer class but there is no custom producer in CDI - a "custom producer" is a custom Bean<?> so it knows which type to return. So +1 to force bean class to return the instance type for custom Beans

            Romain Manni-Bucau (Inactive) added a comment - Class<?> is not enough to know from which module you are so it is not usable (OSGi or EE). I tend to be agree with Mark, beanClass can be the producer class but there is no custom producer in CDI - a "custom producer" is a custom Bean<?> so it knows which type to return. So +1 to force bean class to return the instance type for custom Beans

            Why would you return the same bean class in all the three cases?

            If each WAR bundled a class with a producer method each producing this shared type (let's call it S), these producers would not have S as their bean class for exactly this reason

            Jozef Hartinger added a comment - Why would you return the same bean class in all the three cases? If each WAR bundled a class with a producer method each producing this shared type (let's call it S), these producers would not have S as their bean class for exactly this reason

            Sorry, seems my explanation was too brief

            Imagine you have an EAR with 3 WARs. Each of the WAR files add a Bean with the same class (which is in a shared ear lib), but with different bean attributes and different content.
            The beanclass would be the same for all the 3 Bean<T>, but they are still in 3 totally different EE modules.
            What means getBeanClass() is not usable to distinct the EE modules.

            Mark Struberg (Inactive) added a comment - Sorry, seems my explanation was too brief Imagine you have an EAR with 3 WARs. Each of the WAR files add a Bean with the same class (which is in a shared ear lib), but with different bean attributes and different content. The beanclass would be the same for all the 3 Bean<T>, but they are still in 3 totally different EE modules. What means getBeanClass() is not usable to distinct the EE modules.

            Why not? And why should we restrict this to single WebApp and ignore multi-module scenarios?

            Jozef Hartinger added a comment - Why not? And why should we restrict this to single WebApp and ignore multi-module scenarios?

            But Jozef, this is broken for all manually added Beans. E.g. consider you add a Bean<T> in just one single WebApp. Detecting the module by by only using getBeanClass() just doesn't work.

            Mark Struberg (Inactive) added a comment - But Jozef, this is broken for all manually added Beans. E.g. consider you add a Bean<T> in just one single WebApp. Detecting the module by by only using getBeanClass() just doesn't work.

            The reason why getBeanClass() is defined as it is is modularity. In CDI the concept of "bean class" is used to determine whether a bean in module A is visible to a different bean in module B or not. For producer methods and fields it is the declaring class that determines this, not the return type.

            If you for example have an EAR with multiple wars and one of them defines Foo.class:

            public class Foo {
               @Produces
               String foo() {
                  return "foo";
               }
            }
            

            You want to use Foo.class (the declaring class) to determine visibility of the producer method, not String.class (the return type) as otherwise your producer would be visible from all the other WARs! This is especially the case for custom beans where you have no knowledge if the custom bean represents a producer field/method or not. See section 5.1. Modularity for details.

            Jozef Hartinger added a comment - The reason why getBeanClass() is defined as it is is modularity. In CDI the concept of "bean class" is used to determine whether a bean in module A is visible to a different bean in module B or not. For producer methods and fields it is the declaring class that determines this, not the return type. If you for example have an EAR with multiple wars and one of them defines Foo.class: public class Foo { @Produces String foo() { return "foo" ; } } You want to use Foo.class (the declaring class) to determine visibility of the producer method, not String.class (the return type) as otherwise your producer would be visible from all the other WARs! This is especially the case for custom beans where you have no knowledge if the custom bean represents a producer field/method or not. See section 5.1. Modularity for details.

              Unassigned Unassigned
              struberg Mark Struberg (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

                Created:
                Updated:
                Resolved: