Coverage Report - org.ini4j.spi.BeanTool
 
Classes in this File Line Coverage Branch Coverage Complexity
BeanTool
98%
105/107
93%
75/80
5.385
BeanTool$BeanInvocationHandler
100%
21/21
100%
12/12
5.385
 
 1  
 /*
 2  
  * Copyright 2005,2009 Ivan SZKIBA
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.ini4j.spi;
 17  
 
 18  
 import java.beans.IntrospectionException;
 19  
 import java.beans.Introspector;
 20  
 import java.beans.PropertyDescriptor;
 21  
 
 22  
 import java.io.File;
 23  
 
 24  
 import java.lang.reflect.Array;
 25  
 import java.lang.reflect.Method;
 26  
 import java.lang.reflect.Proxy;
 27  
 
 28  
 import java.net.URI;
 29  
 import java.net.URL;
 30  
 
 31  
 import java.util.TimeZone;
 32  
 
 33  1
 public class BeanTool
 34  
 {
 35  
     private static final String PARSE_METHOD = "valueOf";
 36  1
     private static final BeanTool INSTANCE = ServiceFinder.findService(BeanTool.class);
 37  
 
 38  
     public static final BeanTool getInstance()
 39  
     {
 40  1105
         return INSTANCE;
 41  
     }
 42  
 
 43  
     public void inject(Object bean, BeanAccess props)
 44  
     {
 45  426
         for (PropertyDescriptor pd : getPropertyDescriptors(bean.getClass()))
 46  
         {
 47  
             try
 48  
             {
 49  373
                 Method method = pd.getWriteMethod();
 50  373
                 String name = pd.getName();
 51  
 
 52  373
                 if ((method != null) && (props.propLength(name) != 0))
 53  
                 {
 54  
                     Object value;
 55  
 
 56  291
                     if (pd.getPropertyType().isArray())
 57  
                     {
 58  25
                         value = Array.newInstance(pd.getPropertyType().getComponentType(), props.propLength(name));
 59  95
                         for (int i = 0; i < props.propLength(name); i++)
 60  
                         {
 61  70
                             Array.set(value, i, parse(props.propGet(name, i), pd.getPropertyType().getComponentType()));
 62  
                         }
 63  
                     }
 64  
                     else
 65  
                     {
 66  266
                         value = parse(props.propGet(name), pd.getPropertyType());
 67  
                     }
 68  
 
 69  291
                     method.invoke(bean, value);
 70  
                 }
 71  
             }
 72  1
             catch (Exception x)
 73  
             {
 74  1
                 throw (IllegalArgumentException) (new IllegalArgumentException("Failed to set property: " + pd.getDisplayName()).initCause(
 75  
                         x));
 76  372
             }
 77  
         }
 78  53
     }
 79  
 
 80  
     public void inject(BeanAccess props, Object bean)
 81  
     {
 82  209
         for (PropertyDescriptor pd : getPropertyDescriptors(bean.getClass()))
 83  
         {
 84  
             try
 85  
             {
 86  182
                 Method method = pd.getReadMethod();
 87  
 
 88  182
                 if ((method != null) && !"class".equals(pd.getName()))
 89  
                 {
 90  154
                     Object value = method.invoke(bean, (Object[]) null);
 91  
 
 92  153
                     if (value != null)
 93  
                     {
 94  128
                         if (pd.getPropertyType().isArray())
 95  
                         {
 96  42
                             for (int i = 0; i < Array.getLength(value); i++)
 97  
                             {
 98  31
                                 Object v = Array.get(value, i);
 99  
 
 100  31
                                 if ((v != null) && !v.getClass().equals(String.class))
 101  
                                 {
 102  31
                                     v = v.toString();
 103  
                                 }
 104  
 
 105  31
                                 props.propAdd(pd.getName(), (String) v);
 106  
                             }
 107  
                         }
 108  
                         else
 109  
                         {
 110  117
                             props.propSet(pd.getName(), value.toString());
 111  
                         }
 112  
                     }
 113  
                 }
 114  
             }
 115  1
             catch (Exception x)
 116  
             {
 117  1
                 throw new IllegalArgumentException("Failed to set property: " + pd.getDisplayName(), x);
 118  181
             }
 119  
         }
 120  27
     }
 121  
 
 122  
     @SuppressWarnings("unchecked")
 123  
     public <T> T parse(String value, Class<T> clazz) throws IllegalArgumentException
 124  
     {
 125  1184
         if (clazz == null)
 126  
         {
 127  1
             throw new IllegalArgumentException("null argument");
 128  
         }
 129  
 
 130  1183
         Object o = null;
 131  
 
 132  1183
         if (value == null)
 133  
         {
 134  1
             o = zero(clazz);
 135  
         }
 136  1182
         else if (clazz.isPrimitive())
 137  
         {
 138  869
             o = parsePrimitiveValue(value, clazz);
 139  
         }
 140  
         else
 141  
         {
 142  313
             if (clazz == String.class)
 143  
             {
 144  55
                 o = value;
 145  
             }
 146  258
             else if (clazz == Character.class)
 147  
             {
 148  1
                 o = new Character(value.charAt(0));
 149  
             }
 150  
             else
 151  
             {
 152  257
                 o = parseSpecialValue(value, clazz);
 153  
             }
 154  
         }
 155  
 
 156  1180
         return (T) o;
 157  
     }
 158  
 
 159  
     public <T> T proxy(Class<T> clazz, BeanAccess props)
 160  
     {
 161  184
         return clazz.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { clazz },
 162  
                     new BeanInvocationHandler(props)));
 163  
     }
 164  
 
 165  
     @SuppressWarnings("unchecked")
 166  
     public <T> T zero(Class<T> clazz)
 167  
     {
 168  23
         Object o = null;
 169  
 
 170  23
         if (clazz.isPrimitive())
 171  
         {
 172  13
             if (clazz == Boolean.TYPE)
 173  
             {
 174  2
                 o = Boolean.FALSE;
 175  
             }
 176  11
             else if (clazz == Byte.TYPE)
 177  
             {
 178  2
                 o = Byte.valueOf((byte) 0);
 179  
             }
 180  9
             else if (clazz == Character.TYPE)
 181  
             {
 182  1
                 o = new Character('\0');
 183  
             }
 184  8
             else if (clazz == Double.TYPE)
 185  
             {
 186  3
                 o = new Double(0.0);
 187  
             }
 188  5
             else if (clazz == Float.TYPE)
 189  
             {
 190  1
                 o = new Float(0.0f);
 191  
             }
 192  4
             else if (clazz == Integer.TYPE)
 193  
             {
 194  2
                 o = Integer.valueOf(0);
 195  
             }
 196  2
             else if (clazz == Long.TYPE)
 197  
             {
 198  1
                 o = Long.valueOf(0L);
 199  
             }
 200  1
             else if (clazz == Short.TYPE)
 201  
             {
 202  1
                 o = Short.valueOf((short) 0);
 203  
             }
 204  
         }
 205  
 
 206  23
         return (T) o;
 207  
     }
 208  
 
 209  
     @SuppressWarnings(Warnings.UNCHECKED)
 210  
     protected Object parseSpecialValue(String value, Class clazz) throws IllegalArgumentException
 211  
     {
 212  
         Object o;
 213  
 
 214  
         try
 215  
         {
 216  257
             if (clazz == File.class)
 217  
             {
 218  1
                 o = new File(value);
 219  
             }
 220  256
             else if (clazz == URL.class)
 221  
             {
 222  2
                 o = new URL(value);
 223  
             }
 224  254
             else if (clazz == URI.class)
 225  
             {
 226  249
                 o = new URI(value);
 227  
             }
 228  5
             else if (clazz == Class.class)
 229  
             {
 230  1
                 o = Class.forName(value);
 231  
             }
 232  4
             else if (clazz == TimeZone.class)
 233  
             {
 234  1
                 o = TimeZone.getTimeZone(value);
 235  
             }
 236  
             else
 237  
             {
 238  
 
 239  
                 // TODO handle constructor with String arg as converter from String
 240  
                 // look for "valueOf" converter method
 241  3
                 Method parser = clazz.getMethod(PARSE_METHOD, new Class[] { String.class });
 242  
 
 243  3
                 o = parser.invoke(null, new Object[] { value });
 244  
             }
 245  
         }
 246  2
         catch (Exception x)
 247  
         {
 248  2
             throw (IllegalArgumentException) new IllegalArgumentException().initCause(x);
 249  255
         }
 250  
 
 251  255
         return o;
 252  
     }
 253  
 
 254  
     private PropertyDescriptor[] getPropertyDescriptors(Class clazz)
 255  
     {
 256  
         try
 257  
         {
 258  82
             return Introspector.getBeanInfo(clazz).getPropertyDescriptors();
 259  
         }
 260  0
         catch (IntrospectionException x)
 261  
         {
 262  0
             throw new IllegalArgumentException(x);
 263  
         }
 264  
     }
 265  
 
 266  
     private Object parsePrimitiveValue(String value, Class clazz) throws IllegalArgumentException
 267  
     {
 268  869
         Object o = null;
 269  
 
 270  
         try
 271  
         {
 272  869
             if (clazz == Boolean.TYPE)
 273  
             {
 274  2
                 o = Boolean.valueOf(value);
 275  
             }
 276  867
             else if (clazz == Byte.TYPE)
 277  
             {
 278  1
                 o = Byte.valueOf(value);
 279  
             }
 280  866
             else if (clazz == Character.TYPE)
 281  
             {
 282  1
                 o = new Character(value.charAt(0));
 283  
             }
 284  865
             else if (clazz == Double.TYPE)
 285  
             {
 286  495
                 o = Double.valueOf(value);
 287  
             }
 288  370
             else if (clazz == Float.TYPE)
 289  
             {
 290  1
                 o = Float.valueOf(value);
 291  
             }
 292  369
             else if (clazz == Integer.TYPE)
 293  
             {
 294  367
                 o = Integer.valueOf(value);
 295  
             }
 296  2
             else if (clazz == Long.TYPE)
 297  
             {
 298  1
                 o = Long.valueOf(value);
 299  
             }
 300  1
             else if (clazz == Short.TYPE)
 301  
             {
 302  1
                 o = Short.valueOf(value);
 303  
             }
 304  
         }
 305  1
         catch (Exception x)
 306  
         {
 307  1
             throw (IllegalArgumentException) new IllegalArgumentException().initCause(x);
 308  868
         }
 309  
 
 310  868
         return o;
 311  
     }
 312  
 
 313  1
     static class BeanInvocationHandler extends AbstractBeanInvocationHandler
 314  
     {
 315  
         private final BeanAccess _backend;
 316  
 
 317  
         BeanInvocationHandler(BeanAccess backend)
 318  184
         {
 319  184
             _backend = backend;
 320  184
         }
 321  
 
 322  
         @Override protected Object getPropertySpi(String property, Class<?> clazz)
 323  
         {
 324  952
             Object ret = null;
 325  
 
 326  952
             if (clazz.isArray())
 327  
             {
 328  12
                 int length = _backend.propLength(property);
 329  
 
 330  12
                 if (length != 0)
 331  
                 {
 332  10
                     String[] all = new String[length];
 333  
 
 334  38
                     for (int i = 0; i < all.length; i++)
 335  
                     {
 336  28
                         all[i] = _backend.propGet(property, i);
 337  
                     }
 338  
 
 339  10
                     ret = all;
 340  
                 }
 341  12
             }
 342  
             else
 343  
             {
 344  940
                 ret = _backend.propGet(property);
 345  
             }
 346  
 
 347  952
             return ret;
 348  
         }
 349  
 
 350  
         @Override protected void setPropertySpi(String property, Object value, Class<?> clazz)
 351  
         {
 352  92
             if (clazz.isArray())
 353  
             {
 354  9
                 _backend.propDel(property);
 355  37
                 for (int i = 0; i < Array.getLength(value); i++)
 356  
                 {
 357  28
                     _backend.propAdd(property, Array.get(value, i).toString());
 358  
                 }
 359  
             }
 360  
             else
 361  
             {
 362  83
                 _backend.propSet(property, value.toString());
 363  
             }
 364  92
         }
 365  
 
 366  
         @Override protected boolean hasPropertySpi(String property)
 367  
         {
 368  737
             return _backend.propLength(property) != 0;
 369  
         }
 370  
     }
 371  
 }