11 Replies Latest reply on Jul 13, 2011 6:20 PM by pgmjsd

    Does javax.inject.Provider.get() always return a new instance?

    yangju.richard.yang.pearson.com
      I am trying to create a new bean instance by calling:
      MyType bean = (MyType) source.select(new AnnotationLiteral<MyAnnotation>() { }).get();

      My hope is that everytime I call this, the bean instance I get back is a new one, i.e. not an existing instance sitting somewhere, because MyType is not thread safe.

      So, get() always get me a new instance? If not, how can I get a new one each time?

      Thanks.
        • 1. Re: Does javax.inject.Provider.get() always return a new instance?
          pgmjsd

          Short answer: Yes.  It returns a new instance every time.


          Note that these are going to be managed instances, so they will be tracked by Weld until the context is destroyed.   This can lead to some unexpected behavior when injecting an Instance into an ApplicationScoped bean, as Weld may keep every instance around forever.

          • 2. Re: Does javax.inject.Provider.get() always return a new instance?
            yangju.richard.yang.pearson.com
            Thanks for confirming this.

            I am glad you mention this. I am injecting those beans into an applicationscoped bean right now. I have to use Application scope in my case.

            @ApplicationScoped
            Class MyClass {
            @Inject
                @Any
                Instance<MyType> source;


            MyType myBeans= (MyType) source.select(new AnnotationLiteral<MyAnnotation>() { }).get();

            ...
            }

            So you are saying that there could be many instances of myBeans injected into the application scoped Myclass and managed by weld.
            And these instances will stay as long as the jvm is up.

            Then is there a way for me to pro grammatically decommission/remove the beans?



            • 3. Re: Does javax.inject.Provider.get() always return a new instance?
              pgmjsd

              richard yang wrote on Jul 12, 2011 14:41:


              So you are saying that there could be many instances of myBeans injected into the application scoped Myclass and managed by weld.

              Yes.   Instance provides 'managed beans'.



              And these instances will stay as long as the jvm is up.


              Yes.



              Then is there a way for me to pro grammatically decommission/remove the beans?


              CDI 1.0 currently produces managed instances only.  See https://issues.jboss.org/browse/CDI-139

              • 4. Re: Does javax.inject.Provider.get() always return a new instance?
                haye

                I haven't tried this myself, but couldn't you add @New to the injection point (not sure if it's even allowed)?

                e.g.

                @Any @New Instance<MyType> source;

                ...

                MyType myBeans= source.select(new AnnotationLiteral<MyAnnotation>() { }).get();

                ...

                As long as there is only one bean that is of type MyType and is annotated with @MyAnnotation (context doesn't matter), you should receive a new dependent instance of the bean.

                • 5. Re: Does javax.inject.Provider.get() always return a new instance?
                  haye

                  .. or if CDI wont allow you to add @New at the injection point, you could always do it when you're retrieving the instance


                  MyType myBeans= source.select(new AnnotationLiteral<MyAnnotation>() { }, new AnnotationLiteral<New>() { }).get();


                  • 6. Re: Does javax.inject.Provider.get() always return a new instance?
                    yangju.richard.yang.pearson.com
                    I have verified that  weld does generate a new instance everytime the MyType myBeans= (MyType) source.select(new AnnotationLiteral<MyAnnotation>() { }).get(); gets called.
                    But I don't understand that why Weld does not remove the old instances when a new instance is created. As you can see from the declaration:
                    @Inject
                        @Any
                        Instance<MyType> source;

                    There is only one source declared. Why does weld have to keep all the instances in the scope, when a new one is created.

                    BTW, the @Any @New Instance<MyType> source is not allowed.
                    • 7. Re: Does javax.inject.Provider.get() always return a new instance?
                      yangju.richard.yang.pearson.com
                      If I inject @Inject
                          @Any
                          Instance<MyType> source;
                      into an applicationscoped bean and run the get() over and over, eventually I would get OutOfMemory error. This seems a Weld's design defect to me.
                      • 8. Re: Does javax.inject.Provider.get() always return a new instance?
                        haye

                        Since every time you call Instance.get() a new bean with @Dependent scope is created, the object will linger as long as the @ApplicationScoped bean it is dependent on (MyClass) is still in existence (for the lifetime of your application).


                        I believe you need to re-think how you're doing things. If the method that calls Instance.get() is invoked as part of a request, then you need to make MyType a request-scoped bean. That way, the instance created when you call Instance.get() will be destroyed at the end of the request. You can do this by either annotating MyType with @RequestScoped or you can create a request-scoped producer method that returns the object.


                        • 9. Re: Does javax.inject.Provider.get() always return a new instance?
                          haye

                          Also have a look at this thread http://seamframework.org/Community/DependentBeansDoubts


                          They seem to be dealing with your exact use case.

                          • 10. Re: Does javax.inject.Provider.get() always return a new instance?
                            yangju.richard.yang.pearson.com
                            Thanks, Zak.
                            In my case, I could make the bean non-applicationscoped, but this bean eventually gets injected to a service bean (such as jboss mbean) which is an application scoped singleton. My understanding is (I also verified) that the application scoped service bean promotes all its dependent beans into the same application scope. This is exactly CDI supposed to do. So, mark this bean as RequestScoped or psedo scopes won't help me.

                            This link you provides is exactly what my problem is. I wonder why I did not see this thread before. The other difference is that the reason I use Instance<> is because the instance that I am injecting is unknown  at compiler time. Basically it is based on user's input (a name of class) and then the application will create an instance based on this class name string. I think this is what the CDI programmatically lookup is designed for. I could create a object out of the class name that the user selects by doing Class.newInstance(). Then the new instance is not managed by Weld and I cannot inject anything into it. That is essentially why I use get().

                            I wish CDI did not create a new instance everytime get() is called. I also wish that CDI would find a way to release the previous instance it creates. But those are just my wish.

                            As the discussions in the thread you mentioned, using get() has serious memory problem (potentially), and the Weld documentation should have pointed it out.

                            If you have other ideas for my problem, please let me know.

                            I really appreciate your help, especially the link that you found for me.

                            Richard

                            • 11. Re: Does javax.inject.Provider.get() always return a new instance?
                              pgmjsd

                              richard yang wrote on Jul 13, 2011 14:41:


                              I wish CDI did not create a new instance everytime get() is called.


                              Then don't use Instance, just inject the bean.



                              I also wish that CDI would find a way to release the previous instance it creates. But those are just my wish.


                              You want unmanaged instances.  CDI 1.0 currently supports managed instances only, where the CDI container is guaranteed to call lifecycle methods when the context/bean goes out of scope, etc.   What you want is a Guice / PicoContainer behavior where the container creates the object and then hands it to you: your problem now, buddy.


                              See https://issues.jboss.org/browse/CDI-139


                              Please vote for this issue, maybe it will be included in CDI 1.1.



                              As the discussions in the thread you mentioned, using get() has serious memory problem (potentially), and the Weld documentation should have pointed it out.


                              Yes!  It's very easy to misunderstand CDI's Instance.get() behavior, especially if you have used other DI frameworks.  It goes something like this:



                              • Developer: I want Weld to return me a new instance every time.  How do I do that.

                              • CDI Guru: Inject Instance and use the Instance.get().

                              • Developer: Okay thanks! (goes off and tries it...)

                              • Developer: Hey, Java isn't cleaning up the objects created by Instance.get() because the CDI implementation is pointing at them!  WTF?

                              • CDI Guru: That is because they are managed instances.

                              • Developer: $%#&!#$*(%!