@Override
 public <T extends Annotation> T getAnnotationOnSetter(String name, Class<T> clz) {
   PropertyHolder pp = properties.get(name);
   if (pp == null) return null;
   Method method = pp.getWriteMethod();
   if (method == null) return null;
   return method.getAnnotation(clz);
 }
 public Class<?> getFieldType(String fieldName) {
   PropertyHolder pp = properties.get(fieldName);
   if (pp == null)
     throw new NullPointerException("Can not find PropertyHolder for field: " + fieldName);
   Method m = pp.getWriteMethod();
   if (m == null)
     throw new NullPointerException("Can not find WriterMethod for field: " + fieldName);
   Class<?>[] cs = m.getParameterTypes();
   return cs[0];
 }
 @Override
 public Collection<String> getRwPropertyNames() {
   ArrayList<String> list = new ArrayList<String>();
   for (PropertyHolder pp : properties.values()) {
     if (pp.getReadMethod() != null && pp.getWriteMethod() != null) {
       list.add(pp.getName());
     }
   }
   return list;
 }
 public void setPropertyValue(String fieldName, Object newValue) {
   PropertyHolder pp = properties.get(fieldName);
   if (pp == null)
     throw new NullPointerException(
         "Can not find property '" + fieldName + "' in bean " + obj.getClass().getName());
   Method m = pp.getWriteMethod();
   if (m == null)
     throw new NullPointerException(
         "Can not find set method '" + fieldName + "' in bean " + obj.getClass().getName());
   try {
     m.invoke(obj, new Object[] {newValue});
   } catch (IllegalArgumentException e) {
     StringBuilder sb =
         new StringBuilder("IllegalArgumentException:")
             .append(e.getLocalizedMessage())
             .append('\n');
     sb.append(obj.getClass().getName())
         .append('\t')
         .append(fieldName)
         .append('\t')
         .append(newValue.getClass().getName());
     throw new IllegalArgumentException(sb.toString());
   } catch (IllegalAccessException e) {
     StringBuilder sb =
         new StringBuilder("IllegalAccessException:").append(e.getLocalizedMessage()).append('\n');
     sb.append(obj.getClass().getName())
         .append('\t')
         .append(fieldName)
         .append('\t')
         .append(newValue);
     throw new IllegalArgumentException(sb.toString());
   } catch (InvocationTargetException e) {
     StringBuilder sb =
         new StringBuilder("InvocationTargetException:")
             .append(e.getLocalizedMessage())
             .append('\n');
     sb.append(obj.getClass().getName())
         .append('\t')
         .append(fieldName)
         .append('\t')
         .append(newValue);
     throw new IllegalArgumentException(sb.toString());
   }
 }
 public boolean isWritableProperty(String fieldName) {
   if (fieldName == null) return false;
   PropertyHolder pp = properties.get(fieldName);
   if (pp == null) return false;
   return pp.getWriteMethod() != null;
 }