12 Replies Latest reply: Mar 6, 2013 3:54 AM by skiaddict1 RSS

    Generics, oh dear...

    skiaddict1
      I am writing an accounting system. The various windows need to listen for database changes so they know when to refresh their contents. So, they are DatabaseChangeListeners:
      public interface DatabaseChangedListener extends EventListener
      {
        public void databaseChanged(DatabaseChangedEvent e);
      }
      DatabaseChangedEvent is an abstract superclass of a series of classes, thus:
      abstract public class DatabaseChangedEvent
      {...}
      
      public class AccountsChangedEvent extends DatabaseChangedEvent
      {...}
      
      public class CurrenciesChangedEvent extends DatabaseChangedEvent
      {...}
      etc


      A typical window listens for more than one such type of event; e.g. a window which displays the details about an account, including its transactions, needs to know when the ACCOUNTS database table has changed, but also the TRANSACTIONS and CURRENCIES tables.

      I would like my windows (DatabaseChangedListeners) to be able to do the following:
        @Override
        public void databaseChanged(AccountsChangedEvent e)
        {
          doStuffRelatedToAccounts();
        }
      
        @Override
        public void databaseChanged(CurrenciesChangedEvent e)
        {
          doStuffRelatedToCurrencies();
        }
      
        @Override
        public void databaseChanged(TransactionsChangedEvent e)
        {
          doStuffRelatedToTransactions();
        }
      Of course, this doesn't compile. So I have tried declaring databaseChanged() in the interface as
        public void databaseChanged(<? extends DatabaseChangedEvent> e);
      but I get told "wildcards may only be used as reference parameters". I change the question mark to a T, and I get "cannot resolve symbol T".

      Is it possible to do what I want? (I really hope so; otherwise the only solution I can see is to use instanceof everywhere -- ugh) If so, what magic incantation do I need to use?

      Many TIA!
        • 1. Re: Generics, oh dear...
          EJP
          You need
          public <T extends DatabaseListener> void databaseChanged(T event)
          to fix the syntax error, but I don't see that genericizing the actual methods is going to get you anywhere, as it doesn't really help the caller. I think you need to genericize the interface and have the relevant classes implement the appropriate one for themselves:
          public interface DatabaseChangedListener<T extends DatabaseChangedEvent> extends EventListener
          {
            public void databaseChanged(T e);
          }
          • 2. Re: Generics, oh dear...
            skiaddict1
            Thanks EJP, I've done what you suggest. The interface is now declared as in your post. But now I have another problem! :-[

            I assume that my window classes now need to each have one or more (usually more) "implements" clauses in their top line, saying that they implement the interface in each "form" appropriate? e.g. if a window needs to listen for ACCOUNTS, CURRENCIES and TRANSACTIONS change events, then its top line should look like this:
            public class AWindow extends MyWindow implements DatabaseChangedListener<AccountsChangedEvent>, 
            DatabaseChangedListener<CurrenciesChangedEvent>, DatabaseChangedListener<TransactionsChangedEvent>
            But this doesn't compile! I get "Duplicate class: DatabaseChangedListener".

            Did I assume wrong?
            • 3. Re: Generics, oh dear...
              gimbal2
              So where did you read that it was possible to implement the same interface multiple times?
              • 4. Re: Generics, oh dear...
                skiaddict1
                Gimbal, thanks for your "helpful" post. I haven't read it anywhere. But being able to have multiple, polymorphic versions of my method databaseChanged() is necessary in order to avoid having to use some mechanism like instanceof to respond appropriately to the various possible events that will be fired to the listeners. Furthermore, when I changed the top line of my window class, from
                public class AWindow extends MyWindow implements DatabaseChangedListener
                to
                public class AWindow extends MyWindow implements DatabaseChangedListener<AccountsChangedEvent>
                only the version of databaseChanged() which takes an AccountsChangedEvent stopped having an error signalled on it. This didn't surprise me, since I hadn't yet "introduced" to the compiler the idea that the window class also is a DatabaseChangedListener for e.g. CurrenciesChangedEvents. I therefore went ahead and added
                DatabaseChangedListener<CurrenciesChangedEvent>
                to the top line of my window class. And then the error that I spoke of in my second post was signalled.

                Do you happen to have any ideas as to how I can achieve what I need to?
                • 5. Re: Generics, oh dear...
                  TPD-Opitz
                  The point is:

                  You should not have top level classes implement "Listener"-interfaces at all (accept the class represents nothing else than the listener)

                  Create Listener instances as (anonymous) inner classes.

                  bye
                  TPD
                  • 6. Re: Generics, oh dear...
                    gimbal2
                    TPD Opitz-Consulting com wrote:
                    Create Listener instances as (anonymous) inner classes.
                    That would be the easiest way yes, unless you have like a dozen of them.
                    • 7. Re: Generics, oh dear...
                      TPD-Opitz
                      gimbal2 wrote:
                      TPD Opitz-Consulting com wrote:
                      Create Listener instances as (anonymous) inner classes.
                      That would be the easiest way yes, unless you have like a dozen of them.
                      What exacly is the problem with that?
                      If that dozen Listeners implement the same Interface doing the same on different objects I create a (non anonymous) inner class with a constructor parameter.

                      If I have dozen different Listener interfaces to implement my class may be to meighty...

                      bye
                      TPD
                      • 8. Re: Generics, oh dear...
                        skiaddict1
                        Thanks TPD, for the final piece of the answer. Yes, I should have thought of that myself, but I'm just back to Java coding after a multi-month break from coding due to a tragic event in my life last year. I'm rustier than I would like, both with my codebase and with Java in general. To make matters worse, I have never managed to find a treatment of Java generics that I could get my head around. My mentor, who in his day was a seriously heavy hitter in the industry (and who hasn't been able to work for years -- that's what we get for a youth-obsessed industry and culture in general), says that even he finds the material on generics "dense". (And yes, he has done some pretty cool stuff in Java, so he's not a newbie to it.)

                        If anyone out there knows of a "gentle" treatment on generics, I'd be grateful for any pointers. I don't like having to ask for help and would far prefer to solve my problems myself.
                        • 9. Re: Generics, oh dear...
                          TPD-Opitz
                          Do not excuse!

                          There is no reason to be ashamed because of mistakes and a lag of knowledge as long as you're willing to change that...
                          ;o)

                          bye
                          TPD
                          • 10. Re: Generics, oh dear...
                            gimbal2
                            TPD Opitz-Consulting com wrote:
                            Do not excuse!

                            There is no reason to be ashamed because of mistakes and a lag of knowledge as long as you're willing to change that...
                            ;o)
                            Highly agreed. Making mistakes is a good thing too, there is no better teacher. But you need to attack that with the right attitude; don't start feeling down or ashamed, learn and grow from it. Woohoo, you learned a little!
                            • 11. Re: Generics, oh dear...
                              r035198x
                              If this is a sizeable project then prefer Actions to listeners.
                              • 12. Re: Generics, oh dear...
                                skiaddict1
                                Thanks guys, yes indeed I have learned some from this. In the absence of a "gentle" treatment on generics, I am forming -- gradually -- a kind of "cookbook" for generics, at least that way I have more ideas to try, at my fingertips.