1 2 Previous Next 19 Replies Latest reply on Sep 21, 2015 3:31 AM by Martin Kouba

    Do I need to explicitly release a contextual JDialog created with CDI?

    Marcos Antonio Novice

      - Weld 3.0.0.Alpha13

       

      Suppose that MyDialog extends javax.swing.JDialog. Consider this code:

       

      MyDialog dialog = CDI.current().select(MyDialog.class).get();

      dialog.setVisible(true);

      dialog.dispose();

       

      Questions:

       

      • Does it need to explicitly release dialog with CDI or the above code is already fine? If so, which class and method of CDI do I need to call? (Consider that after the user closes the dialog. I don't need it to be around anymore)
      • According to the code, which context is dialog living in?


      Cross-posted: http://stackoverflow.com/questions/32417201/do-i-need-to-explicitly-release-a-contextual-jdialog-created-with-cdi

        • 1. Re: Do I need to explicitly release a contextual JDialog created with CDI?
          Martin Kouba Master

          Hi Marcos,

           

          • context - if you don't specify a scope the bean is @Dependent (see also http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#default_scope)
          • release - the instance is a dependent object of the CDI container (org.jboss.weld.environment.se.WeldContainer in this particular case) and will be destroyed when the container is shut down
          • destroy - you could make use of  javax.enterprise.inject.Instance.destroy(), e.g. CDI.current().destroy(dialog)
          • 2. Re: Do I need to explicitly release a contextual JDialog created with CDI?
            Marcos Antonio Novice

            Martin Kouba escreveu:

             

            Hi Marcos,

             

            • context - if you don't specify a scope the bean is @Dependent (see also http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#default_scope)
            • release - the instance is a dependent object of the CDI container (org.jboss.weld.environment.se.WeldContainer in this particular case) and will be destroyed when the container is shut down
            • destroy - you could make use of  javax.enterprise.inject.Instance.destroy(), e.g. CDI.current().destroy(dialog)

            If I understood well, according to your answer, it is advisable to destroy the dialog, but I don't need to because it has a @Dependent scope and will be destroyed by the container anyway. Is this correct? Also, if I explicitly destroy release the instance the container will call the method annotated with @PreDestroy early, right?

            • 3. Re: Do I need to explicitly release a contextual JDialog created with CDI?
              Martin Kouba Master
              If I understood well, according to your answer, it is advisable to destroy the dialog, but I don't need to because it has a @Dependent scope and will be destroyed by the container anyway. Is this correct? Also, if I explicitly destroy release the instance the container will call the method annotated with @PreDestroy early, right?

              It's hard to answer without the deeper knowledge of your applicaton. However, if you only have one dialog per application (i.e. if the app lifecycle is similar to: 1. Start the CDI container, 2. Open the dialog, 3. Close the dialog, 4. Shutdown the CDI container) it's OK to let the container to destroy the bean instance (and call @PreDestroy) during shutdown. On the other hand, if you open/close many dialogs in your application, it's better to destroy the bean instances manually, otherwise you may run out of resources.

              • 5. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                Marcos Antonio Novice

                Even though I have already marked this issue as answered there is still a doubt in my mind that is really very related to this issue, that's why I wouldn't like to start a new discussion for it. I'm going to try to make it as simple as possible.

                 

                Consider this bean:

                 

                public class MyBean

                {

                    @PreDestroy

                    void release()

                    {

                        System.out.println("releasing");

                    }

                }

                 

                Now consider this short lived method of some class:

                 

                private void foo()

                {

                    CDI.current().select(MyBean.class).get();

                }

                 

                As you can see the method gets a contextual instance of MyBean and returns without saving a reference to the instance anywhere. The instance in this case is a @Dependent instance. In the application I'm developing I'll really need to get managed instances using this pattern (using CDI.current().select(...).get()). My question is: in this particular example, will the MyBean#release() method ever be called by CDI before the CDI container is shutdown (I know it will be called on shutdown)? I just want to make sure of this, because if I have to manually release all CDI instances I get this way. what's the point of using CDI? I'm just thinking here that CDI is smart enough to see that the instance if not reachable anymore and release the bean, calling its @PreDestroy method.

                 

                I really would like to have your help about this once more. This is very important to me. Thank you in advance.

                • 6. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                  Martin Kouba Master

                  My question is: in this particular example, will the MyBean#release() method ever be called by CDI before the CDI container is shutdown (I know it will be called on shutdown)?

                  No, the bean instance will not be destroyed before the container shuts down. You'll have to destroy it explicitly. Make sure you're using Weld 2.2.11+ as there was an issue with destroying dependent instances through CDI.current().destroy(), see also WELD-1917.

                  • 7. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                    Marcos Antonio Novice

                    Martin Kouba escreveu:

                     

                    My question is: in this particular example, will the MyBean#release() method ever be called by CDI before the CDI container is shutdown (I know it will be called on shutdown)?

                    No, the bean instance will not be destroyed before the container shuts down. You'll have to destroy it explicitly. Make sure you're using Weld 2.2.11+ as there was an issue with destroying dependent instances through CDI.current().destroy(), see also WELD-1917.

                    Hello, Martin. Once again, thank you for the answer.

                     

                    I'm using Weld 3.0.0.Alpha13 (CDI 2.0). I don't know how is the CDI implementation provided by Weld, but I was just thinking to myself if the implementation was something like this: inside Weld put beans in a kind of java.lang.ref.SoftReference so that when memory is low all the dependent beans that were not released explicitly and were not reachable anymore were reclaimed by the GC, avoiding a memory leak and taking away the burden from developers of releasing the beans manually. Could you or someone else comment on this? Is this even feasible?

                    • 8. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                      Martin Kouba Master

                      Well, the problem is we have to destroy the contextual instance properly, i.e. call @PreDestroy callbacks and release the CreationalContext. I'm not sure this is doable only by means of soft references. In any case, the CDI spec itself allows to destroy such instances - see also 6.4.2. Destruction of objects with scope @Dependent. But it's not required so you would end up with unportable application anyway.

                      • 9. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                        Marcos Antonio Novice

                        The last paragraph of 6.4.2. says:

                         

                        "Finally, the container is permitted to destroy any @Dependent scoped contextual instance at any time if the instance is no longer referenced by the application (excluding weak, soft and phantom references)."

                         

                        If Weld implemented this, I was done. This is the way I was thinking any CDI provider would behave. This is so neat that I think I wouldn't even care to stick only to Weld, not having a portable application. What you said until now in this topic is true: @Dependent instances are not destroyed automatically. I've made a lot of tests in my application and confirmed this. I even created a background thread to call regularly System.gc() in the background but the lost @Dependent instances are not destroyed (they're destroyed only when the CDI container is shutdown, of course).

                         

                        Maybe I'm only left with the option to use @ApplicationScoped beans in my application. With Java we don't have to take care of releasing our instances, but using CDI it seems that I will have to do something similar with almost all my @Dependent instances. It's clearly a step back and a high price to pay to use the services provided by CDI. It seems like I'm programming in C++ or C. It's error prone to say the least. When I'm working with CDI in a Java EE application, I don't have this concern. Everything in Java EE is CDI aware, but trying to add support to CDI in a Java SE application is becoming very challenging because of this issue. Maybe a workaround would be welcome, but I can think of none right now.

                        • 10. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                          Martin Kouba Master

                          It's clearly a step back and a high price to pay to use the services provided by CDI. It seems like I'm programming in C++ or C. It's error prone to say the least. When I'm working with CDI in a Java EE application, I don't have this concern. Everything in Java EE is CDI aware, but trying to add support to CDI in a Java SE application is becoming very challenging because of this issue.

                          I don't think it's an issue of dependent. Dependent beans are just "dependent" and IMHO should not be used like that. The problem is there are no suitable built-in scopes in Java SE. Unlike in Java EE where the built-in scopes align with the lifecycle of EE components (@RequestScoped, @SessionScoped, etc.). Ideally, each Java SE application should define its own custom scope that would correspond to various application requests/events. In Weld SE ther is a thread context which could handy in some situations.

                          • 11. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                            Martin Kouba Master

                            By the way, in Weld there is the following optimization - CreatinalContext does not hold references to dependent instances that:

                            • do not define @PreDestroy callbacks
                            • are not intercepted
                            • don't have a disposer method declared
                            • don't have such a dependent transitive dependency

                            E.g. the following code would work as you expected - the dependent Foo is used and becomes unreachable afterwards:

                            class Foo {
                              void ping() {
                              }
                            }
                            class Main {
                              public static void main(String[] args) {
                                try(WeldContainer container = new Weld().initialize()) {
                                  // This is the same as CDI.current().select().get()
                                  container.select(Foo.class).get().ping();
                                  // From this point Foo instance is unreachable
                                  ...
                                }
                              }
                            }
                            

                            See also WELD-920, WELD-1076 and WELD-1996

                            • 12. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                              Marcos Antonio Novice

                              Martin Kouba escreveu:

                               

                              By the way, in Weld there is the following optimization - CreatinalContext does not hold references to dependent instances that:

                              • do not define @PreDestroy callbacks
                              • are not intercepted
                              • don't have a disposer method declared
                              • don't have such a dependent transitive dependency

                               

                              In my opinion, this is too much restriction. I would definitely want my dependent beans to have itens 1, 2, and 4 of this list if I needed. Specially @PreDestroy and transitive dependency.

                              • 13. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                                Marcos Antonio Novice

                                Martin Kouba escreveu:

                                 

                                It's clearly a step back and a high price to pay to use the services provided by CDI. It seems like I'm programming in C++ or C. It's error prone to say the least. When I'm working with CDI in a Java EE application, I don't have this concern. Everything in Java EE is CDI aware, but trying to add support to CDI in a Java SE application is becoming very challenging because of this issue.

                                I don't think it's an issue of dependent. Dependent beans are just "dependent" and IMHO should not be used like that. The problem is there are no suitable built-in scopes in Java SE. Unlike in Java EE where the built-in scopes align with the lifecycle of EE components (@RequestScoped, @SessionScoped, etc.). Ideally, each Java SE application should define its own custom scope that would correspond to various application requests/events. In Weld SE ther is a thread context which could handy in some situations.

                                This is a great answer. It explains very well why things are hard with CDI in Java SE regarding dependent beans - lack of suitable scopes is one of the reasons. It seems that in some way the developer will have to do a lot of work if he wants a full 100% CDI Java SE application. For the time being I only have three or four application scoped beans in my application. Before CDI I had an abstract factory from them. Now the abstract factory is gone, but I still have to manually instantiate some other classes that I would like to have the CDI services, like injection.

                                 

                                I would not use the @ThreadScoped context, as I don't want my sources dependent of any CDI provider, but I would, as I said, use only Weld if it released the dependent beans automatically if they're not reachable by the application anymore. By the way, I don't know why Weld doesn't implement this. It is in the specification, so it is not going agains anything here. What's the point of a CDI provider to retain a lost instance in memory if it's not used anywhere else? Maybe CDI could even provide in the specification a configuration for this if the developer wanted this behavior. I don't know, just my opinion, but this would definitely increase the use of CDI by developers of Java SE applications (myself included).

                                • 14. Re: Do I need to explicitly release a contextual JDialog created with CDI?
                                  Martin Kouba Master

                                  I would not use the @ThreadScoped context, as I don't want my sources dependent of any CDI provider...

                                  Maybe this should be standardized in CDI 2.0.

                                  By the way, I don't know why Weld doesn't implement this. It is in the specification, so it is not going agains anything here. What's the point of a CDI provider to retain a lost instance in memory if it's not used anywhere else?

                                  Because if you have a dependent bean with @PreDestroy callback you can't simply use a java.lang.ref.WeakReference - the container is required to destroy the bean instance correctly. I'm not aware of any reliable way of doing this in Java. But I'm ready to explore any tips

                                  1 2 Previous Next