How to use a lis of parameterized property names and type for a java bean

4.1k Views Asked by At

Say I have a bean

public class SomeBean{
     List<String> messages;
     List<Integer> scores;
     String id;
     int  number;

.... }

I am using the following code to process or dump the propreties

        BeanInfo beanInfo = Introspector.getBeanInfo(beanClass, Object.class);
        PropertyDescriptor descriptors[] = beanInfo.getPropertyDescriptors();
        int stop = descriptors.length;
        for (int i = 0; i < stop; ++i) {
            PropertyDescriptor descriptor = descriptors[i];
            logger.info(descriptor.getName() + " : " + descriptor.getPropertyType().getName() + ", writemethod :" + descriptor.getWriteMethod());

        }

That I want to be able to get the parameterized type for the "scores" and "messages". When I ruin the code, the value for the " descriptor.getPropertyType().getName()" is "java.util.List" for both messages and scores .

How do I tell if the property descriptor for "message" is referring to List<String> and for "scores" is referring to List<Integer> ?

2

There are 2 best solutions below

0
On BEST ANSWER

There are two cases.

The first case is when the property's parameterized type is not known at compile time:

public class Pair<A, B> {
  public A getFirst() { ... }
  public B getSecond() { ... }
}

In this case, you cannot know at compile time, and is what @darioo is talking about.

The second case is yours, when the properties' type parameters are known at runtime. The code below should help you figure out exactly what you want to do:

BeanInfo beanInfo = Introspector.getBeanInfo(beanClass, Object.class);
PropertyDescriptor descriptors[] = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor d : descriptors) {
    final Type type = d.getReadMethod().getGenericReturnType();
    if (type instanceof ParameterizedType) {
        ParameterizedType pt = (ParameterizedType) type;
        System.out.println(d.getDisplayName());
        for (Type atp : pt.getActualTypeArguments()) {
            System.out.println("  " + atp);
        }
    }
}

The key here is to get the read or write method, and use the API Method.getGenericReturnType() or Method.getParameterTypes() respectively.

Note that dealing with java.lang.reflect.Type generically gets quite tedious/tricky, consider, for example:

public Map<Nation, Map<A extends PostCode, B extends Location>> getGlobalPostCodes() { ... }
1
On

As long as the fields have fully specified compile-time types like in your example (List<String> and not something like List<T>, that is) you can use reflection to get this information:

for (Field field : SomeBean.class.getDeclaredFields()) {
  Type type = field.getGenericType();
  System.out.println(field.getName() + ": " + type);
  if (type instanceof ParameterizedType) {
    ParameterizedType parameterized = (ParameterizedType) type;
    Type raw = parameterized.getRawType(); // This would be Class<List>, say
    Type[] typeArgs = parameterized.getActualTypeArguments();
    System.out.println(Arrays.toString(typeArgs));
  }
}

Wasn't sure if you could do this with the bean-related code, but it looks like you can.