2 Ekim 2019 Çarşamba

BeanUtils Sınıfı

Giriş
Şu satırı dahil ederiz.
import org.apache.commons.beanutils.BeanUtils;
Maven
Şu satırı dahil ederiz.
<dependency>
  <groupId>commons-beanutils</groupId>
  <artifactId>commons-beanutils</artifactId>
  <version>1.9.3</version>
 </dependency>
BeanUtils ve PropertyUtils birbirlerine benziyorlar.

Ortak Noktalar
1. Her iki sınıf ta erişilmeye çalışılan sınıfın public olmasını ve no argument constructor'a sahip olmasını ister. Açıklaması şöyle. Eğer bu koşullar sağlanmazsa BeanUtils InvocationTargetException fırlatır.
The class must be public, and provide a public constructor that accepts no arguments. This allows tools and applications to dynamically create new instances of your bean, without necessarily knowing what Java class name will be used ahead of time,...
2. Hem BeanUtils hem de PropertyUtils Introspection kullanarak getter/setter metodları kullanır. Açıklaması şöyle.
The BeanUtils package relies on introspection rather than reflection. This means that it will find only JavaBean compliant properties.

There are some subtleties of this specification that can catch out the unwary:

- A property can have only one set and one get method. Overloading is not allowed.

- The java.beans.Introspector searches widely for a custom BeanInfo class. If your class has the same name as another with a custom BeanInfo (typically a java API class) then the Introspector may use that instead of creating via reflection based on your class. If this happens, the only solution is to create your own BeanInfo.
Elimizde şöyle bir kod olsun.
public class Bean {
  protected Boolean happy;

  public void setHappy(Boolean happy) {
    this.happy = happy;
  }
}
Şöyle yaparız.
Bean bean = new Bean();
BeanUtils.setProperty(bean, "happy", true);
Farklar
1. BeanUtils ve PropertyUtils hemen hemen aynı şeyleri yapıyor gibi görünüyor, ancak aralarında önemli bir fark var.

BeanUtils verilen parametreyi setter metodundaki tipe çevirmeye çalışıyor. PropertyUtils bunu yapmıyor. BeanUtils için açıklama şöyle.
Set the specified property value, performing type conversions as required to conform to the type of the destination property.
Aynı şeyi söyleyen bir başka açıklama şöyle.
There is however a big difference between these two classes which I came across while using these classes: BeanUtils does an automatic type conversion and PropertyUtils does not.
For example: with BeanUtils you can set a double valued property by providing a String. BeanUtils will check the type of the property and convert the String into a double. With PropertyUtils you always have to provide a value object of the same type as the property, so in this example a double.
Örneği field tipi int olsun ancak elimizdeki atanacak parametre tipi String olsun ve setter metodu
void setFieldA(int value) olsun. Bu durumda BeanUtils setter metodu bulabilir ancak PropertyUtils bulamaz ve PropertyUtils IllegalArgumentException fırlatır.

Bu durum XML'den okuma yapınca setter çağırmak için BeanUtils'i kullanmayı daha kolay yapıyor.

Örnek - String parametreyi int setter'a çevirme
Elimizde şöyle bir kod olsun.
public static class Obj {
  private int number;
  private String string;

  public void setNumber(int number) {
    this.number = number;
  }
  public void setString(String string) {
    this.string = string;
  }

  public String toString() {
    return "number=" + number + " string=" + string;
  }
}
Şöyle yaparız
String[] values = new String[] { "1", "two" };
String[] properties = new String[] { "number", "string" };

Obj obj = new Obj();

for (int i = 0; i < properties.length; i++) {
  BeanUtils.setProperty(obj, properties[i], values[i]);
}

System.out.println("obj=" + obj);
Çıktı olarak şunu alırız
obj=number=1 string=two
2. BeanUtils var olmayan bir field'ı set etmeye çalışınca exception fırlatmaz hata da vermez. PropertyFields ise NoSuchMethodException fırlatır.

copyProperties metodu - destinaton + original
İmzası şöyle.
public static void copyProperties(Object dest, Object orig)
                           throws IllegalAccessException,
                                  InvocationTargetException)
Örnek
Şöyle yaparız.
BeanUtils.copyProperties(dest, source);
Örnek
Şöyle yaparız. Exception yakalamayı göstermedim.
Ch409F fromBean = new Ch409F();
...
Ch409DifF toBean = new Ch409DifF();
...
BeanUtils.copyProperties(toBean, fromBean);
Örnek
Eğer bean'ler aynı değilse exception fırlatır. Elimizde iki alan ismine sahip iki bean olsun.
BeanDTO {
  NestedBeanDTO nestedProperty;
}

Bean {
  NestedBean nestedProperty;
}
Şöyle yaparız.
BeanUtils.copyProperties(Bean, BeanDTO) 
Exception olarak şunu alırız.
argument type mismatch - had objects of type "NestedBeanDTO" but expected signature 
"NestedBean"
copyProperties metodu - destination + original + properties
Sadece verilen alanları kopyalar.
Örnek
Şöyle yaparız
Student student = new Student();
student.setName("Tom");
student.setAge(18);
Student newStudent = new Student();
BeanUtils.copyProperties(student,newStudent);
System.out.println(newStudent);

getConvertUtils metodu
Elimizde şöyle bir kod olsun.
private static class CustomBeanConverter implements Converter {

  @Override
  public <T> T convert(Class<T> aClass, Object o) {
    Object output = null;
    try {
      output = aClass.getDeclaredConstructor().newInstance();
      BeanUtils.copyProperties(output, o);
    } catch (IllegalAccessException | InvocationTargetException |
             NoSuchMethodException | InstantiationException e) {
      e.printStackTrace();
    }
    return (T)output;
  }
}
Şöyle yaparız.
BeanUtilsBean.getInstance().getConvertUtils().register(
  new CustomBeanConverter(), NestedBean.class);

BeanUtils.copyProperties(Bean, BeanDTO)
getProperty metodu
Açıklaması şöyle.
... Thus when we extract a property or event name from the middle of an existing Java name, we normally convert the first character to lower case*case 1. However to support the occasional use of all upper-case names, we check if the first two characters*case 2 of the name are both upper case and if so leave it alone. So for example,
'FooBah" becomes 'fooBah'
'Z' becomes 'z'
'URL' becomes 'URL'
We provide a method Introspector.decapitalize which implements this conversion rule
Eğer field'a erişemiyorsa şu exception fırlatılır.
Unknown property 'User_Name' on class 'User'".
But w
Örnek
Şöyle yaparız.
Object object = ...;
Object str = BeanUtils.getProperty(object,"count");
Örnek
Elimizde şöyle bir kod olsun. getProperty() metodunu "User_Name" olarak çağırırsak exception fırlatır. Çünkü getUser_Name() and setUser_Name() metodlarına bakarak property'nin "user_Name" olması beklenir.
public class User {

  private String User_Name;

  public String getUser_Name() {
    return this.User_Name;
  }

  public void setUser_Name(String user_Name) {
    this.User_Name = user_Name;
  }
}
Düzeltmek için şöyle yaparız
public class User {

  private String userName;

  public String getUserName() {
    return userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }

  public static void main(String[] args)
    throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    User bean = new User();
    bean.setUserName("name");
    System.out.println(BeanUtils.getProperty(bean, "userName"));
  }
}
populate metodu
Birden fazla alanı aynı anda set etmek için kullanılır.

Örnek
Elimizde şöyle bir kod olsun
class A {
  rivate String name;

  ublic void setName(String name){
    this.name = name;
  

  public String getName(){
    return this.name;
  }
}
Şöyle yaparız.
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"); 
setProperty metodu
İmzası şöyle.
public static void setProperty(Object bean,
                               String name,
                               Object value)
                        throws IllegalAccessException,
                               InvocationTargetException

    Parameters:
        bean - Bean on which setting is to be performed
        name - Property name (can be nested/indexed/mapped/combo)
        value - Value to be set 
Örnek
Şöyle yaparız.
BeanUtils.setProperty(customer,"firstName","Paul Young");
Örnek
Şöyle yaparız.
Object reflectedInstance = ...;
Object objectFromResponse = ...;

Field[] fields = reflectedInstance.getClass().getDeclaredFields();
for(Field field: fields) {

  Object objectFromResponse = ...;

  if(if(field.getName().equals("...")) {

     BeanUtils.setProperty(reflectedInstance, field.getName(), objectFromResponse);
}

Hiç yorum yok:

Yorum Gönder