12 Replies Latest reply: Jun 21, 2010 7:31 AM by 791266 RSS

    getting the T.class

    800386
      since a generic class defines a T which is a Type, am i right to say that we should be able to do something like this: java.lang.Class c = T.class; ?

      i'm trying to convert some vb code into java and i've come across this problem that i cant do a T.class.

      the current way that i'm doing is that i created an additional parameter of type T and call the .getClass() of the parameter (which effectively giving me the class object of T) but i feel that its pretty "ugly", is there a better solution?
        • 1. Re: getting the T.class
          800387
          At runtime most type information is erased. So, my guess is you should rethink your design. What is it you are trying to do?

          - Saish
          • 2. Re: getting the T.class
            800386
               
            
            //desired solution:
            protected <T> T F1(java.awt.Component component) {
                    F2(component, T.class);
                    return (T) F3(component);
                }    
            
            //usage:
            F1(jlabel);  // line 10
            
            
            
            //current approach (i don't want to do it this way if i can):
                protected <T> T F1(java.awt.Component component, java.lang.Class c) {
                    F2(component, c);
                    return (T) F3(component);
                }    
            //usage:
            F1(jlabel, javax.swing.JLabel.class);
            so im fairly confused by line 10, in vb we have to explicitly say that T is a JLabel as such: F1(of JLabel)(jlabel), in Java we didn't, so what exactly is T?
            • 3. Re: getting the T.class
              800387
              You have not really bought any type safety with your methodology (note that you are having to cast). To me it seems like you are forcing the use of generics for no real reason. What is it you are trying to do? Also, by convention, method names are lower [camel-case|http://en.wikipedia.org/wiki/CamelCase].

              - Saish
              • 4. Re: getting the T.class
                800268
                It seems like you want, assuming F3 returns its parameter:
                protected <T extends Component> T someUsefulMethodName(T component) {
                  // do something
                 return component;
                }
                • 5. Re: getting the T.class
                  800386
                  even with T extends Component, i could not solve the problem of extracting the type of T, without having to specify an additional argument

                  ok to give a summary of what i'm trying to achieve, basically this is what i have: AwtComponent class that wraps a java.awt.Component object and manipulates it through proxy functions providing an API to do mild animation. since the proxy functions are irrelevant, i will scrape them off. the important functions are these:

                  public java.awt.Component GetInterior() :returns the wrapped java.awt.Component object
                  protected AwtComponent SetInterior(java.awt.Component component) :the return object of Set is not void but the object itself, this is to allow chaining sets (e.g. i want to set the location, size, background color etc i can do it with awt_instance.Set1().Set2().Set3(), anyway this is irrelevant )

                  A subclass of AwtComponent (e.g. AwtContainer) will override GetInterior() and return a subclass of java.awt.Component instead of java.awt.Component. similarly SetInterior will be overrided in such a way that if the component passed in is not a java.awt.Container, an exception will be thrown.

                  to streamline this process, i have an argument checker which goes like this:
                  public static void EnsureType(int argument_number, Object object, java.lang.Class desired_class) {
                          if (object == null) {
                              throw new MyException.ArgumentNull(argument_number);
                          } else if (!desired_class.isAssignableFrom(object.getClass())) {
                              throw new MyException.ArgumentType(argument_number, object, desired_class);
                          }
                      }
                  example usage: EnsureType(1, component, java.awt.Container.class)

                  Essentially what it does is that it takes the object component and throws a RuntimeException if component cannot be casted to the 3rd argument which is java.awt.Container (the first argument is not relevant here, its for exception error checking purposes)



                  since AwtComponent will have many children and grandchildren, each descendant will have to Override their parent's GetInterior and SetInterior

                  Lets take a child as an example, called AwtContainer:
                      @Override
                      public java.awt.Container GetInterior() {
                          return (java.awt.Container)super.GetInterior();
                      }
                      @Override
                      protected AwtContainer SetInterior(java.awt.Component component) {
                          MyException.Misc.ArgumentChecker.EnsureType(1, component, java.awt.Container.class);
                          return  (AwtContainer)super.SetInterior(component);
                      }
                  although the GetInterior seems pretty easy to override, the SetInterior gets a bit longer (yes its pretty long even with our streamline argumentchecker). AwtComponent is preparing itself for many many children and if each children will have to do this its pretty annoying. So AwtComponent decides to streamline function overriding even furthur with its 2 other functions:

                  *protected <T extends java.awt.Component> T OverrideGetInterior()
                  protected <T> T OverrideSetInterior(java.awt.Component component, java.lang.Class interior_class)
                  *
                  with these 2 functions, now each children only need to do this when they override:
                     @Override
                      public java.awt.Container GetInterior() {
                          return OverrideGetInterior();
                      }
                  
                      @Override
                      protected AwtContainer SetInterior(java.awt.Component component) {
                          return OverrideSetInterior(component, AwtContainer.class);
                      }
                  Below is an extract of the code for classes:

                  AwtComponent Class
                  package MyGUI.Abstract;
                  
                  public abstract class AwtComponent {
                  
                      private java.awt.Component component;
                  
                      public AwtComponent(java.awt.Component component) {
                          SetInterior(component);
                      }
                  
                      public java.awt.Component GetInterior() {
                          return component;
                      }
                  
                      protected <T extends java.awt.Component> T OverrideGetInterior() {
                          return (T) GetInterior();
                      }
                  
                      protected AwtComponent SetInterior(java.awt.Component component) {
                          this.component = component;
                          return this;
                      }
                  
                      protected <T> T OverrideSetInterior(java.awt.Component component, java.lang.Class interior_class) {
                          MyException.Misc.ArgumentChecker.EnsureType(1, component, interior_class);
                          return (T) SetInterior(component);
                      }
                  }
                  AwtContainer Class
                  package MyGUI.Abstract;
                  
                  public abstract class AwtContainer extends MyGUI.Abstract.AwtComponent {
                  
                      public AwtContainer(java.awt.Container container) {
                          super(container);
                          GetInterior().setLayout(null);
                      }
                  
                      @Override
                      public java.awt.Container GetInterior() {
                          return OverrideGetInterior();
                      }
                  
                      @Override
                      protected AwtContainer SetInterior(java.awt.Component component) {
                          return OverrideSetInterior(component, java.awt.Container.class);
                      }
                  // example function:
                      public MyGUI.Abstract.AwtComponent Add(MyGUI.Abstract.AwtComponent component) {
                          GetInterior().add(component.GetInterior());
                          return component;
                      }
                  }
                  JComponent Class
                  package MyGUI.Abstract;
                  
                  public class JComponent extends MyGUI.Abstract.AwtContainer {
                  
                      public JComponent(javax.swing.JComponent jcomponent) {
                          super(jcomponent);
                      }
                  
                      @Override
                      public javax.swing.JComponent GetInterior() {
                          return OverrideGetInterior();
                      }
                  
                      @Override
                      protected JComponent SetInterior(java.awt.Component component) {
                       return OverrideSetInterior(component, javax.swing.JComponent.class);
                      }
                  }
                  ArgumentChecker Class
                  package MyException.Misc;
                  
                  public class ArgumentChecker {
                  
                      public static void EnsureType(int argument_number, Object object, java.lang.Class desired_class) {
                          if (object == null) {
                              throw new MyException.ArgumentNull(argument_number);
                          } else if (!desired_class.isAssignableFrom(object.getClass())) {
                              throw new MyException.ArgumentType(argument_number, object, desired_class);
                          }
                      }
                  }
                  irrelevant but maybe useful, the exception classes:
                  Argument Class
                  package MyException;
                  
                  public class Argument extends java.lang.IllegalArgumentException {
                  
                      private int argument_number;
                  
                      public int GetArgumentNumber() {
                          return argument_number;
                      }
                  
                      public Argument(int argument_number, Object error_object, String message) {
                         super(message);
                          this.argument_number = argument_number;
                      }
                  
                      public Argument(int argument_number, Object error_object) {
                          this(argument_number, error_object, "Argument number " + argument_number + " is invalid.");
                      }
                  }
                  ArgumentNull Class
                  package MyException;
                  
                  public class ArgumentNull extends MyException.Argument {
                  
                      public ArgumentNull(int argument_number) {
                          super(argument_number, null, "Argument " + argument_number + " must not be null");
                      }
                  }
                  ArgumentType Class
                  package MyException;
                  
                  public class ArgumentType extends MyException.Argument {
                  
                      public ArgumentType(int argument_number, Object error_object, java.lang.Class desired_class) {
                          super(argument_number, error_object, "Argument " + argument_number + " is of type " + error_object.getClass().getName() + " but the desired_type is " + desired_class.getName());
                      }
                  }
                  Edited by: Pacerier on Jun 16, 2010 4:51 PM
                  • 6. Re: getting the T.class
                    800268
                    Then you want to make the AWTComponent class generic on itself which isn't that pretty. There's probably already a framework out there that does fluent/declarative SWing building or something similar to what you seem to be making (or see JavaFX or Groovy's SwingBuilder).
                    import java.awt.Color;
                    import java.awt.Component;
                    import java.awt.EventQueue;
                    
                    import javax.swing.JFrame;
                    import javax.swing.JLabel;
                    
                    public class AWTComponent<C extends Component, T extends AWTComponent<C, T>> {
                    
                        public static void main(String[] args) {
                            EventQueue.invokeLater(new Runnable() {
                                public void run() {
                                    new WFrame()
                                        .setTitle("Test")
                                        .setContent(new WLabel()
                                            .setText("Look at me being all fluent!")
                                            .setForeground(Color.RED)
                                        ).show();
                                }
                            });
                        }
                    
                        private final C component;
                    
                        protected AWTComponent(C component) {
                            this.component = component;
                        }
                    
                        public C getComponent() {
                            return component;
                        }
                    
                        public T setForeground(Color foreground) {
                            component.setForeground(foreground);
                            return getThis();
                        }
                    
                        // no 'this' type literal available
                        @SuppressWarnings("unchecked")
                        protected T getThis() {
                            return (T) this;
                        }
                    
                        public static class WLabel extends AWTComponent<JLabel, WLabel> {
                    
                            protected WLabel() {
                                super(new JLabel());
                            }
                    
                            public WLabel setText(String text) {
                                getComponent().setText(text);
                                return this;
                            }
                        }
                    
                        public static class WFrame extends AWTComponent<JFrame, WFrame> {
                    
                            protected WFrame() {
                                super(new JFrame());
                            }
                    
                            public WFrame setTitle(String title) {
                                getComponent().setTitle(title);
                                return this;
                            }
                    
                            public WFrame setContent(AWTComponent<?, ?> component) {
                                getComponent().getContentPane().add(component.getComponent());
                                return this;
                            }
                    
                            public WFrame show() {
                                JFrame frame = getComponent();
                                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                                frame.pack();
                                frame.setLocationRelativeTo(null);
                                frame.setVisible(true);
                                return this;
                            }
                        }
                    }
                    • 7. Re: getting the T.class
                      800387
                      You also have a bad design smell. Why are you duplicating the existing AWT inheritance hierarchy? My guess is you can get away with an interface or two for what you actually want to accomplish (and what the various UI components have in common that you want to invoke). If you find yourself with a lot of instanceof checks or casts, then you likely need to hit the drawing board again.

                      - Saish
                      • 8. Re: getting the T.class
                        800386
                        actually i could do away with the instanceof checks, its there to ensure the developer of the child class (myself) uses the protected method SetInterior appropriately. other developers who extend AwtComponent may choose not to override SetInterior to provide instanceof checks if they are sure that they will throw a correct arg in protected SetInterior()

                        anyways i was wondering about this for quite some time, is instanceof supposedly a "fast" or "slow" operation?
                        • 9. Re: getting the T.class
                          800387
                          It's all relative. However, it is highly unlikely that this would be a scaling bottleneck for you. If you were running a simulation where each millions of calls to instance of occurred per unit of time, then I would worry about it. Heed the advice of Knuth, "Premature optimization is the root of all evil."

                          - Saish
                          • 10. Re: getting the T.class
                            800386
                            ok thanks for the reply
                            • 11. Re: getting the T.class
                              800387
                              You are welcome. Best of luck.

                              - Saish
                              • 12. This Thread is now moved
                                791266
                                Note: This thread was originally posted in the [New To Java|http://forums.sun.com/forum.jspa?forumID=54] forum, but moved to this forum for closer topic alignment.