29

Is there any standard way to access Java Bean Property like

class A {
   private String name;

   public void setName(String name){
       this.name = name;
   }

   public String getName(){
       return this.name;
   }

}

So can I access this java bean property name using Reflection API so that when I change the value of property the methods of getName and setName are called automatically when I set and get values of that property

Troydm
  • 2,642
  • 3
  • 24
  • 35

4 Answers4

47

You question is very unclear, but if I get it:

Yes. The java.beans package has the so called Introspector. There you can read the properties of a bean.

BeanInfo info = Introspector.getBeanInfo(Bean.class);
PropertyDescriptor[] pds = info.getPropertyDescriptors();

You can find the desired PropertyDescriptor by its name and you can call getReadMethod().invoke(..)

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 11
    I prefer this method because you need no dependencies. – Cyril Sochor Oct 15 '12 at 14:41
  • an other advantage of this way is that the java.lang.reflect.Method can be re-used so that getting/writing the value of the same property on different instances of the same class can be much faster, reading a property is around 100x faster compared to using BeanUtils and 20x Spring BeanWrapper. I like also the answer of perdi-estaquel because of code example – Testo Testini Apr 24 '21 at 01:25
45

What you need is the BeanInfo / Introspector mechanism (see Bozho's answer). However, it's hell to use this directly, so you can use one of the Libraries that offer property-based access. The best-known is probably Apache Commons / BeanUtils (another one is Spring's BeanWrapper abstraction)

Example code:

A someBean = new A();

// access properties as Map
Map<String, Object> properties = BeanUtils.describe(someBean);
properties.set("name","Fred");
BeanUtils.populate(someBean, properties);

// access individual properties
String oldname = BeanUtils.getProperty(someBean,"name");
BeanUtils.setProperty(someBean,"name","Barny"); 
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • just for the ignorant (me), why not just call someBean.setName("Fred")? – simpatico May 02 '11 at 12:44
  • 1
    @simpatico for a single known property, obviously, yes. But if you want to manage access to many different properties of many different types of Objects, use bean properties – Sean Patrick Floyd May 02 '11 at 12:48
  • 1
    thank you. I buy it if the properties are set in a file one loads and then just calls BeanUtils.populate(someBean, properties); But I'd never in practice call set("name", "Fred") while I can call setName("Fred") directly (I no yours is just example code). – simpatico May 02 '11 at 13:30
  • 1
    @simpatico: If you've got the type information to know at compile time that there is a `setName` method, that's what you should use. Otherwise, a bean introspector makes life easier as it can reduce a lot of coupling. Moreover, the cost of using introspection isn't actually too high (outside of critical inner loops). – Donal Fellows May 02 '11 at 13:41
3

Use a java.beans.PropertyDescriptor

In your case:

A a = new A();
PropertyDescriptor nameProperty = new PropertyDescriptor("name", A.class);
nameProperty.getWriteMethod().invoke(a, "potato");
System.out.println(nameProperty.getReadMethod().invoke(a));
Perdi Estaquel
  • 819
  • 1
  • 6
  • 21
1

I have tried BeanUtils as well as PropertyDescriptors because I did not have the information on the class that was passed to my method. I did not even know the data types of the properties passed and so setting values became difficult. I know that BeanUtils should do the conversion automatically for the property and set it but it was not saving the data for me. So finally, I had to rely on getting the fields. Here is what I did:

Field[] fields = className.getDeclaredFields();
for (int i=0; i<fields.length ;i++)
{
  String element = fields[i].getName();
  String propertyType = fields[i].getType().getName();
  fields[i].setAccessible(true);
  if(propertyType.equalsIgnoreCase("java.lang.Integer"))
    {
      fields[i].set(mypojoObj, Integer.parseInt(parameterValue));
    }
    else
    {
      fields[i].set(mypojoObj, parameterValue);
    }
 }

I did a similar switch-case to convert all property types to correct types. When fetching from the page, request.getParameter(paramname) was always returning String so this conversion worked for me. Any better options for direct data conversion will be really helpful.

Manish
  • 11
  • 1