This discussion is archived
1 2 Previous Next 22 Replies Latest reply: Sep 9, 2010 5:45 PM by 843798 RSS

Runtime type of Collection contents?

843798 Newbie
Currently Being Moderated
I'm pretty certain I know the answer to this question, but anyway:

In a JavaBean editor, one property of the bean may be a collection of (potentially editable) beans. To edit the property I can display the appropriate editor if I can determine the type of the bean in the collection. A dirty but effective solution is to sample the collection and see what's actually in it. But in the case of an empty collection that isn't possible. (One function of the editor is to add a new bean to the collection.)

It seems that my only alternative is myCollection.getClass().getTypeParameters(), which tells you what the parameters were when the type was declared, e.g. for Vector<E>, "E", which obviously isn't any help, although it is consonant with the rule that the type parameter "disappears at runtime". (In other words, that Java is a statically typed language.)

I just want to confirm that I'm not missing something.


(Btw, a potential, though labor-intensive, solution is to set the collection element type in a BeanInfo attribute. So it's not like this is a dead end. I just want to confirm that I'm understanding it correctly.)

TIA
  • 1. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    It's true, you can't get to that info at runtime.
  • 2. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    Thanks. Attribute it is, then.


    <sigh> Sometimes I just hate being right.
  • 3. Re: Runtime type of Collection contents?
    jtahlborn Expert
    Currently Being Moderated
    that is true of the returned collection. however, i believe if you inspect the type information on the bean itself, you should be able to get the bounds of the collection. depending on how the collection was defined, that may or may not be useful. e.g.
    public class MyMainBean
    {
      public Collection<Object> objCollection;
      public Collection<MyOtherBean> otherCollection;
    }
    in this example class, you should be able to determine that objCollection can hold Objects and otherCollection can hold MyOtherBean. if all your collections are typed with Object, then this won't be useful information. but, if you have specific types on the collection (like MyOtherBean), you should be able to get reasonable info.
  • 4. Re: Runtime type of Collection contents?
    800330 Explorer
    Currently Being Moderated
    I favour List<E> and Collection<E> properties in my beans. I experienced once before, that such preference is not always benificial: in SOAP context you loose the info on E easily. DMF's example is the second in which type information is lost. Would this be a reason to favour the good old array for properties in beans you plan to expose at runtime?
  • 5. Re: Runtime type of Collection contents?
    jtahlborn Expert
    Currently Being Moderated
    isocdev_mb wrote:
    I favour List<E> and Collection<E> properties in my beans.
    that makes sense if the bean itself is parameterized, otherwise, not so much. regardless, the bounds for the types should be available, just in a different place.
    I experienced once before, that such preference is not always benificial: in SOAP context you loose the info on E easily. DMF's example is the second in which type information is lost. Would this be a reason to favour the good old array for properties in beans you plan to expose at runtime?
    not sure i followed that completely, but regardless, how do arrays solve the problem? if you have a generic type in an array or in a collection, you still have the same information available. (and in general arrays are a pain to work, i generally avoid them if at all possible).
  • 6. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    Hi,
    This is how I found out the type of class in Collection. Not sure right or wrong. It is working in our project. May be fail in various scenarios. This might give you a direction
    public Class getClassType(Field field) throws ClassNotFoundException {
              Type type = field.getGenericType();
              String strType = null;
              if (type instanceof ParameterizedType) {
                   strType = Arrays.toString(((ParameterizedType) type).getActualTypeArguments()).substring(7, Arrays.toString(((ParameterizedType) type).getActualTypeArguments()).length() - 1);
              }
    
              if (strType != null) {
                   Class klass = Class.forName(strType);
                   return klass;
              }
              return null;
         }
    Thanx & regards
    Aniruddha Dutta Chowdhury
  • 7. Re: Runtime type of Collection contents?
    800330 Explorer
    Currently Being Moderated
    jtahlborn wrote:
    isocdev_mb wrote:
    I favour List<E> and Collection<E> properties in my beans.
    that makes sense if the bean itself is parameterized, otherwise, not so much. regardless, the bounds for the types should be available, just in a different place.
    Ah sorry, where E is not a type specifier but a concrete other class. So something like:
       class ProposalBean {
          private List<Source> sources;
          public List<Source> getSources() {return sources;}
       }
    versus
       class ProposalBean {
          Source[] sources;
          public Source[] getSources(){return sources;}
       }
  • 8. Re: Runtime type of Collection contents?
    jtahlborn Expert
    Currently Being Moderated
    isocdev_mb wrote:
    Ah sorry, where E is not a type specifier but a concrete other class. So something like:
    class ProposalBean {
    private List<Source> sources;
    public List<Source> getSources() {return sources;}
    }
    yes, and like i said, the class information for that bean (either the Method or Field) should allow you to determine that the Source class is the type of objects held in the sources property.
  • 9. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    jtahlborn wrote:
    yes, and like i said, the class information for that bean (either the Method or Field) should allow you to determine that the Source class is the type of objects held in the sources property.
    I'll bite. How?
       class ProposalBean {
          private List<Source> sources = new Vector<Source>();
          public List<Source> getSources() {return sources;}
       }
    PropertyDescriptor.getPropertyType("sources") returns Vector.class. An inspection of Vector.class with Class.getTypeParameters() returns [E]. Nothing about type Source so no way to retrieve its BeanInfo.

    Edited by: DMF. on Sep 8, 2010 5:03 PM
  • 10. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    jtahlborn wrote:
    ... how do arrays solve the problem? if you have a generic type in an array or in a collection, you still have the same information available. (and in general arrays are a pain to work, i generally avoid them if at all possible).
    With an array, so long as you use a concrete type the type is always available through getClass().getComponentType(), even when it's empty.

    But you're right. That's not nearly enough to adopt them as the standard aggregate type for JavaBeans.
  • 11. Re: Runtime type of Collection contents?
    jtahlborn Expert
    Currently Being Moderated
    DMF. wrote:
    jtahlborn wrote:
    yes, and like i said, the class information for that bean (either the Method or Field) should allow you to determine that the Source class is the type of objects held in the sources property.
    I'll bite. How?
    class ProposalBean {
    private List<Source> sources = new Vector<Source>();
    public List<Source> getSources() {return sources;}
    }
    PropertyDescriptor.getPropertyType("sources") returns Vector.class. An inspection of Vector.class with Class.getTypeParameters() returns [E]. Nothing about type Source so no way to retrieve its BeanInfo.
    maybe my last post wasn't very clear. when i said the information was available from the "bean", i meant the class itself. the information should be available from the relevant Field/Method (e.g. the example code in [reply 6|http://forums.sun.com/thread.jspa?messageID=11045136#11045136] )

    Edited by: jtahlborn on Sep 9, 2010 7:53 AM
  • 12. Re: Runtime type of Collection contents?
    jtahlborn Expert
    Currently Being Moderated
    DMF. wrote:
    jtahlborn wrote:
    ... how do arrays solve the problem? if you have a generic type in an array or in a collection, you still have the same information available. (and in general arrays are a pain to work, i generally avoid them if at all possible).
    With an array, so long as you use a concrete type the type is always available through getClass().getComponentType(), even when it's empty.
    right. i initially thought that this post was referring to an array of a Generic type, in which case the getComponentType() wouldn't help you much. (that said, the type is available if the array is empty, but not if it is null).
  • 13. Re: Runtime type of Collection contents?
    EJP Guru
    Currently Being Moderated
    I initially thought that this post was referring to an array of a Generic type
    There is no such thing in Java.
  • 14. Re: Runtime type of Collection contents?
    843798 Newbie
    Currently Being Moderated
    AH HA! It works, but don't ask me why (yet). Here's some test code, using a Method rather than a Field since accessor methods are available through Introspection while Fields aren't:
    public class ATestBean {
        
        public static void main ( final String[] args ) throws Throwable 
        {
            ATestBean bean = new ATestBean();
        }
        
        public ATestBean ( ) throws Throwable {  super();
            Method m = getClass().getDeclaredMethod("getCollection", new Class[0] );
            Class<?> c = getClassType( m );
        }
    
        public Collection<AConcreteClass> getCollection()  {
            return null;
        }
        
        public Class<?> getClassType(final Method meth ) throws Throwable {
            Type type = meth.getGenericReturnType();
            String strType = null;
            if (type instanceof ParameterizedType) {
                String actual = Arrays.toString( ((ParameterizedType)type).getActualTypeArguments() ); 
                   // actual <- "[class com.x.y.z.AConcreteClass]"
                strType = actual.substring( 7, actual.length()-1 );
            }
            if (strType != null) {
                Class<?> klass = Class.forName(strType);
                return klass;
            }
            return null;
        }
        
    }
    Learn something new every day. Thanks.


    Hmmm, looks like Introspector is due for an update...
1 2 Previous Next