1 7 package com.inversoft.beans; 8 9 10 import java.lang.reflect.Array ; 11 import java.util.ArrayList ; 12 import java.util.List ; 13 import java.util.Map ; 14 import java.util.WeakHashMap ; 15 16 import com.inversoft.util.ObjectTools; 17 import com.inversoft.util.ReflectionException; 18 import com.inversoft.util.ReflectionTools; 19 import com.inversoft.util.typeconverter.TypeConversionException; 20 21 22 92 public class JavaBean { 93 94 97 static final boolean CACHING = true; 98 99 102 static Map cache = new WeakHashMap (); 103 104 protected Class beanClass; 105 106 107 115 public static JavaBean getInstance(Class beanClass) { 116 if (!CACHING) { 118 return new JavaBean(beanClass); 119 } 120 121 synchronized (cache) { 122 JavaBean javaBean = (JavaBean) cache.get(beanClass); 124 if (javaBean == null) { 125 javaBean = new JavaBean(beanClass); 126 cache.put(beanClass, javaBean); 127 } 128 129 return javaBean; 130 } 131 } 132 133 134 137 protected JavaBean() { 138 } 139 140 150 public JavaBean(Class beanClass) { 151 this.beanClass = beanClass; 152 } 153 154 165 public JavaBean(String beanClass) throws BeanException { 166 try { 167 this.beanClass = Class.forName(beanClass); 168 } catch (ClassNotFoundException cnfe) { 169 throw new BeanException(cnfe); 170 } 171 } 172 173 174 177 public Class getBeanClass() { 178 return beanClass; 179 } 180 181 185 protected void setBeanClass(Class beanClass) { 186 this.beanClass = beanClass; 187 } 188 189 192 public String getClassName() { 193 return beanClass.getName(); 194 } 195 196 218 public BeanProperty getBeanProperty(String propertyName) throws BeanException { 219 220 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 221 222 if (!ni.nested) { 224 return findProperty(ni.localPropertyName); 225 } 226 227 JavaBean child = findChildJavaBean(ni.localPropertyName, null); 229 230 return child.getBeanProperty(ni.nestedPropertyName); 232 } 233 234 258 public IndexedBeanProperty getIndexedBeanProperty(String propertyName) 259 throws BeanException { 260 261 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 262 263 if (!ni.nested) { 265 266 BeanProperty bp = findProperty(ni.localPropertyName); 270 if (!(bp instanceof IndexedBeanProperty)) { 271 throw new BeanException("Property is not indexed"); 272 } 273 274 return (IndexedBeanProperty) bp; 275 } 276 277 JavaBean child = findChildJavaBean(ni.localPropertyName, null); 279 280 return child.getIndexedBeanProperty(ni.nestedPropertyName); 282 } 283 284 299 public NestedBeanProperty getNestedBeanProperty(String propertyName) 300 throws BeanException { 301 return new NestedBeanProperty(propertyName, beanClass); 302 } 303 304 324 public boolean isBeanPropertyIndexed(String propertyName) throws BeanException { 325 326 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 327 328 if (!ni.nested) { 330 331 BeanProperty bp = findProperty(ni.localPropertyName); 333 return (bp instanceof IndexedBeanProperty); 334 } 335 336 JavaBean child = findChildJavaBean(ni.localPropertyName, null); 338 339 return child.isBeanPropertyIndexed(ni.nestedPropertyName); 341 } 342 343 356 public void checkBeanProperty(String propertyName, Class type) 357 throws BeanException { 358 359 BeanProperty prop = getBeanProperty(propertyName); 360 361 if (!prop.getPropertyType().isAssignableFrom(type)) { 362 throw new BeanException(type.getName() + " is not a valid type for" + 363 " the bean property named " + propertyName); 364 } 365 } 366 367 382 public JavaBean getChildJavaBean(String propertyName) throws BeanException { 383 384 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 385 386 JavaBean child = findChildJavaBean(ni.localPropertyName, null); 388 389 return ((ni.nested) ? 392 child.getChildJavaBean(ni.nestedPropertyName) : child); 393 } 394 395 403 public Object instantiate() throws BeanException { 404 try { 405 return ReflectionTools.instantiate(beanClass); 406 } catch (ReflectionException re) { 407 throw new BeanException(re); 408 } 409 } 410 411 412 416 433 public Object getPropertyValue(String propertyName, Object bean) 434 throws BeanException { 435 return getPropertyValue(propertyName, bean, (List ) null, false); 436 } 437 438 455 public Object getPropertyValue(String propertyName, Object bean, boolean strict) 456 throws BeanException { 457 return getPropertyValue(propertyName, bean, (List ) null, strict); 458 } 459 460 487 public Object getPropertyValue(String propertyName, Object bean, int[][] indices) 488 throws BeanException { 489 List list = convertArray(indices); 490 return getPropertyValue(propertyName, bean, list, false); 491 } 492 493 520 public Object getPropertyValue(String propertyName, Object bean, int[][] indices, 521 boolean strict) 522 throws BeanException { 523 List list = convertArray(indices); 524 return getPropertyValue(propertyName, bean, list, strict); 525 } 526 527 554 public Object getPropertyValue(String propertyName, Object bean, List indices) 555 throws BeanException { 556 return getPropertyValue(propertyName, bean, indices, false); 557 } 558 559 583 public Object getPropertyValue(String propertyName, Object bean, List indices, 584 boolean strict) 585 throws BeanException { 586 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 587 JavaBeanTools.PropertyInfo pi = 588 JavaBeanTools.retrievePropertyInfo(ni.localPropertyName); 589 590 List subList = indices; 591 boolean listEmpty = (indices == null || indices.size() == 0); 592 if (pi.indices == null && !listEmpty) { 593 pi.indices = (List ) indices.get(0); 594 subList = indices.subList(1, indices.size()); 595 } 596 597 Object value = getLocalPropertyValue(pi, bean); 598 if (ni.nested) { 599 if (value != null) { 600 601 JavaBean child = JavaBean.getInstance(value.getClass()); 602 value = child.getPropertyValue(ni.nestedPropertyName, value, subList, 603 strict); 604 } else if (strict) { 605 throw new BeanException("Null property value encountered for " + 606 "strict JavaBean. Property name was: " + propertyName); 607 } 608 } 609 610 return value; 611 } 612 613 632 public void setPropertyValue(String propertyName, Object bean, Object value) 633 throws BeanException { 634 try { 635 setPropertyValue(propertyName, bean, (List ) null, value, false, false); 636 } catch (TypeConversionException tce) { 637 assert false : "FATAL: should never throw TypeConversionException" + 638 " because this method does no conversion"; 639 } 640 } 641 642 667 public void setPropertyValue(String propertyName, Object bean, Object value, 668 boolean convert) 669 throws BeanException, TypeConversionException { 670 setPropertyValue(propertyName, bean, (List ) null, value, convert, false); 671 } 672 673 698 public void setPropertyValue(String propertyName, Object bean, Object value, 699 boolean convert, boolean strict) 700 throws BeanException, TypeConversionException { 701 setPropertyValue(propertyName, bean, (List ) null, value, convert, strict); 702 } 703 704 731 public void setPropertyValue(String propertyName, Object bean, int[][] indices, 732 Object value, boolean convert) 733 throws BeanException, TypeConversionException { 734 List list = convertArray(indices); 735 setPropertyValue(propertyName, bean, list, value, convert, false); 736 } 737 738 765 public void setPropertyValue(String propertyName, Object bean, int[][] indices, 766 Object value, boolean convert, boolean strict) 767 throws BeanException, TypeConversionException { 768 List list = convertArray(indices); 769 setPropertyValue(propertyName, bean, list, value, convert, strict); 770 } 771 772 799 public void setPropertyValue(String propertyName, Object bean, List indices, 800 Object value, boolean convert) 801 throws BeanException, TypeConversionException { 802 recurseToSet(propertyName, bean, indices, value, convert, false); 803 } 804 805 832 public void setPropertyValue(String propertyName, Object bean, List indices, 833 Object value, boolean convert, boolean strict) 834 throws BeanException, TypeConversionException { 835 recurseToSet(propertyName, bean, indices, value, convert, strict); 836 } 837 838 842 private void recurseToSet(String propertyName, Object bean, List indices, 843 Object value, boolean convert, boolean strict) 844 throws BeanException, TypeConversionException { 845 JavaBeanTools.NameInfo ni = JavaBeanTools.splitNameFront(propertyName); 846 JavaBeanTools.PropertyInfo pi = 847 JavaBeanTools.retrievePropertyInfo(ni.localPropertyName); 848 849 boolean hasIndices = (indices != null && indices.size() > 0); 850 List subList = null; 851 852 if (pi.indices == null && hasIndices) { 853 pi.indices = (List ) indices.get(0); 854 subList = indices.subList(1, indices.size()); 855 } 856 857 if (ni.nested) { 858 Object beanInstance = getLocalPropertyValueCreate(pi, bean, strict); 859 860 JavaBean child = JavaBean.getInstance(beanInstance.getClass()); 861 child.recurseToSet(ni.nestedPropertyName, beanInstance, subList, 862 value, convert, strict); 863 } else { 864 setLocalPropertyValue(pi, bean, value, convert, strict); 865 } 866 } 867 868 869 873 876 final List convertArray(int[][] indices) { 877 List list = null; 878 if (indices != null && indices.length > 0) { 879 list = new ArrayList (); 880 for (int i = 0; i < indices.length; i++) { 881 List subList = new ArrayList (); 882 list.add(subList); 883 884 for (int j = 0; j < indices[i].length; j++) { 885 subList.add(new Integer (indices[i][j])); 886 } 887 } 888 } 889 890 return list; 891 } 892 893 900 private BeanProperty findProperty(String propertyName) throws BeanException { 901 BeanProperty property; 902 903 try { 905 property = IndexedBeanProperty.getInstance(propertyName, beanClass); 906 } catch (BeanException be) { 907 property = BeanProperty.getInstance(propertyName, beanClass); 908 } 909 910 return property; 911 } 912 913 918 private JavaBean findChildJavaBean(String propertyName, Class type) 919 throws BeanException { 920 921 if (type == null) { 922 BeanProperty prop = findProperty(propertyName); 923 type = prop.getPropertyType(); 924 } 925 926 return JavaBean.getInstance(type); 928 } 929 930 private boolean hasMoreIndices(List indices, int count) { 931 return (indices != null && count < indices.size()); 932 } 933 934 939 private Object getLocalPropertyValue(JavaBeanTools.PropertyInfo pi, Object bean) 940 throws BeanException { 941 BeanProperty bp = findProperty(pi.propertyName); 942 943 int count = 0; 944 boolean indexed = (bp instanceof IndexedBeanProperty); 945 Object value; 946 IndexedBeanProperty ip; 947 Object rootIndex; 948 if (indexed) { 949 if (!hasMoreIndices(pi.indices, count)) { 950 throw new BeanException("Property named: " + pi.propertyName + 951 " is indexed, but no indices supplied"); 952 } 953 954 ip = (IndexedBeanProperty) bp; 955 rootIndex = pi.indices.get(0); 956 value = ip.getPropertyValue(bean, rootIndex); 957 count++; 958 } else { 959 value = bp.getPropertyValue(bean); 960 } 961 962 if (value != null && hasMoreIndices(pi.indices, count)) { 963 int length = pi.indices.size(); 964 Object ds = value; 965 Object subDS = null; 966 while (ObjectTools.isDataStructure(ds) && (count < length)) { 967 try { 968 subDS = ObjectTools.getValueFromCollection(ds, 969 pi.indices.get(count)); 970 } catch (IllegalArgumentException iae) { 971 throw new BeanException(iae.getMessage() + " for property " + 972 "named: " + pi.propertyName); 973 } 974 975 count++; 976 if (ObjectTools.isDataStructure(subDS) && (count < length)) { 977 ds = subDS; 978 } 979 } 980 981 value = subDS; 982 } 983 984 return value; 985 } 986 987 992 private Object getLocalPropertyValueCreate(JavaBeanTools.PropertyInfo pi, 993 Object bean, boolean strict) 994 throws BeanException { 995 BeanProperty bp = findProperty(pi.propertyName); 996 997 int count = 0; 998 boolean indexed = (bp instanceof IndexedBeanProperty); 999 Object value; 1000 IndexedBeanProperty ip = null; 1001 Object rootIndex = null; 1002 1003 if (indexed) { 1006 if (!hasMoreIndices(pi.indices, count)) { 1007 throw new BeanException("Property named: " + pi.propertyName + 1008 " is indexed, but no indices supplied"); 1009 } 1010 1011 ip = (IndexedBeanProperty) bp; 1012 rootIndex = pi.indices.get(0); 1013 value = ip.getPropertyValue(bean, rootIndex); 1014 count++; 1015 } else { 1016 value = bp.getPropertyValue(bean); 1017 } 1018 1019 if (hasMoreIndices(pi.indices, count)) { 1024 int length = pi.indices.size(); 1025 ArrayAndIndex ai = traverseDataStructure(value, bp, ip, rootIndex, pi, 1026 bean, count, indexed, strict); 1027 1028 try { 1029 value = ObjectTools.getValueFromCollection(ai.array, 1030 pi.indices.get(length - 1)); 1031 } catch (IllegalArgumentException iae) { 1032 throw new BeanException(iae.getMessage() + " for property " + 1033 "named: " + pi.propertyName); 1034 } catch (IndexOutOfBoundsException ioobe) { 1035 value = null; 1037 } 1038 1039 Class type = ai.array.getClass(); 1040 if (value == null && type.isArray()) { 1041 if (strict) { 1042 throw new BeanException("Null value encountered and strictness" + 1043 " set for property named: " + pi.propertyName); 1044 } 1045 1046 try { 1047 value = ReflectionTools.instantiate(type.getComponentType()); 1048 ObjectTools.setValueIntoCollection(ai.array, 1049 pi.indices.get(length - 1), value); 1050 } catch (ReflectionException re) { 1051 throw new BeanException(re); 1052 } catch (IllegalArgumentException iae) { 1053 throw new BeanException(iae.getMessage() + " for property " + 1054 "named: " + pi.propertyName); 1055 } 1056 } else if (value == null) { 1057 throw new BeanException("Null value encountered for property " + 1058 "named: " + pi.propertyName + ". Unable to create because" + 1059 " a data structure was encountered of type: " + type.getName() + 1060 ". Only arrays can be auto-generated."); 1061 } 1062 } else if (value == null) { 1063 if (strict) { 1064 throw new BeanException("Null value encountered and strictness" + 1065 " set for property named: " + pi.propertyName); 1066 } 1067 1068 try { 1069 Class type = bp.getPropertyType(); 1070 value = ReflectionTools.instantiate(type); 1071 } catch (ReflectionException re) { 1072 throw new BeanException(re); 1073 } 1074 1075 if (indexed) { 1076 ip.setPropertyValue(bean, rootIndex, value, false); 1077 } else { 1078 bp.setPropertyValue(bean, value, false); 1079 } 1080 } 1081 1082 return value; 1083 } 1084 1085 1088 private void setLocalPropertyValue(JavaBeanTools.PropertyInfo pi, Object bean, 1089 Object value, boolean convert, boolean strict) 1090 throws BeanException { 1091 BeanProperty bp = findProperty(pi.propertyName); 1092 int count = 0; 1093 boolean indexed = (bp instanceof IndexedBeanProperty); 1094 IndexedBeanProperty ip = null; 1095 Object rootIndex = null; 1096 1097 if (indexed) { 1100 if (!hasMoreIndices(pi.indices, count)) { 1101 throw new BeanException(); 1102 } 1103 count++; 1104 rootIndex = pi.indices.get(0); 1105 ip = (IndexedBeanProperty) bp; 1106 } 1107 1108 if (hasMoreIndices(pi.indices, count)) { 1112 Object propertyValue; 1113 if (indexed) { 1114 propertyValue = ip.getPropertyValue(bean, rootIndex); 1115 } else { 1116 propertyValue = bp.getPropertyValue(bean); 1117 } 1118 1119 ArrayAndIndex ai = traverseDataStructure(propertyValue, bp, ip, 1120 rootIndex, pi, bean, count, indexed, strict); 1121 1122 Class type = ai.array.getClass(); 1124 if (convert && type != null && type.isArray() && 1125 type.getComponentType() != null) { 1126 value = bp.convertParameter(value, bean, type.getComponentType()); 1127 } 1128 1129 try { 1130 ObjectTools.setValueIntoCollection(ai.array, 1131 pi.indices.get(ai.lastIndex), value); 1132 } catch (IllegalArgumentException iae) { 1133 throw new BeanException(iae.getMessage() + " for property " + 1134 "named: " + pi.propertyName); 1135 } 1136 } else { 1137 if (indexed) { 1138 ip.setPropertyValue(bean, rootIndex, value, convert); 1139 } else { 1140 bp.setPropertyValue(bean, value, convert); 1141 } 1142 } 1143 } 1144 1145 1171 private ArrayAndIndex traverseDataStructure(Object ds, BeanProperty bp, 1172 IndexedBeanProperty ip, Object rootIndex, JavaBeanTools.PropertyInfo pi, 1173 Object bean, int startIndex, boolean indexed, boolean strict) 1174 throws BeanException { 1175 int stopIndex = pi.indices.size() - 1; 1176 Class type = null; 1177 boolean create = (ds == null); 1178 boolean isNull = (ds == null); 1179 if (isNull) { 1180 type = bp.getPropertyType(); 1181 if (!type.isArray()) { 1182 throw new BeanException("Unable to determine type to create for" + 1183 " property named: " + pi.propertyName + ". Property type is " + 1184 type.getName() + " and only properties whose type are arrays" + 1185 " can be auto-generated."); 1186 } 1187 } else { 1188 Object subDS = ds; 1189 boolean inDS = ObjectTools.isDataStructure(ds); 1190 while (inDS && startIndex < stopIndex) { 1191 try { 1192 subDS = ObjectTools.getValueFromCollection(ds, 1193 pi.indices.get(startIndex)); 1194 } catch (IllegalArgumentException iae) { 1195 throw new BeanException(iae.getMessage() + " for property" + 1196 " named: " + pi.propertyName); 1197 } 1198 1199 inDS = ObjectTools.isDataStructure(subDS); 1200 if (inDS) { 1201 ds = subDS; 1202 startIndex++; 1203 } 1204 } 1205 1206 if (subDS == null && ds.getClass().isArray()) { 1207 type = ds.getClass(); 1208 create = true; 1209 } 1210 } 1211 1212 if (create) { 1213 if (strict) { 1214 throw new BeanException("Null value encountered and strictness" + 1215 " set for property named: " + pi.propertyName); 1216 } 1217 1218 ObjectTools.ArrayInfo ai; 1219 try { 1220 ai = ObjectTools.createArray(type, pi.indices, startIndex); 1221 } catch (IllegalArgumentException iae) { 1222 throw new BeanException("Non-integer indices for property named: " + 1223 pi.propertyName); 1224 } 1225 1226 if (isNull) { 1227 if (indexed) { 1228 ip.setPropertyValue(bean, rootIndex, ai.array, false); 1229 } else { 1230 bp.setPropertyValue(bean, ai.array, false); 1231 } 1232 } else { 1233 try { 1234 ObjectTools.setValueIntoCollection(ds, pi.indices.get(startIndex), 1235 ai.array); 1236 } catch (IllegalArgumentException iae) { 1237 throw new BeanException(iae.getMessage() + " for property " + 1238 "named: " + pi.propertyName); 1239 } 1240 } 1241 1242 ds = ai.array; 1243 } 1244 1245 while (ObjectTools.isArray(ds) && startIndex < stopIndex) { 1246 int index = ((Integer ) pi.indices.get(startIndex)).intValue(); 1247 Object subDS = Array.get(ds, index); 1248 if (ObjectTools.isArray(subDS)) { 1249 ds = subDS; 1250 startIndex++; 1251 } 1252 } 1253 1254 ArrayAndIndex ai = new ArrayAndIndex(); 1255 ai.array = ds; 1256 ai.lastIndex = startIndex; 1257 1258 return ai; 1259 } 1260 1261 private class ArrayAndIndex { 1262 Object array; 1263 int lastIndex; 1264 } 1265} | Popular Tags |