1 3 package jodd.petite; 4 5 import jodd.petite.scope.Scope; 6 import jodd.petite.scope.SingletonScope; 7 import jodd.petite.scope.DefaultScope; 8 import jodd.petite.meta.PetiteBean; 9 import jodd.petite.meta.PetiteBeanRef; 10 import jodd.util.StringUtil; 11 import jodd.introspector.DefaultIntrospector; 12 import jodd.introspector.ClassDescriptor; 13 import jodd.bean.BeanUtil; 14 15 import java.util.*; 16 import java.lang.reflect.Field ; 17 import java.lang.reflect.Constructor ; 18 import java.lang.annotation.Annotation ; 19 20 23 public class PetiteContainer { 24 25 27 40 public Object getBean(String name) { 41 return getBean(name, new HashMap<String , Object >()); 42 } 43 44 47 protected Object getBean(String name, Map<String , Object > acquiredBeans) { 48 49 Object bean = acquiredBeans.get(name); 54 if (bean != null) { 55 if (bean == Void.TYPE) { 56 throw new PetiteException("Cycle dependecies on constructor injection detected!"); 57 } 58 return bean; 59 } 60 61 BeanDef def = beanNames.get(name); 63 if (def == null) { 64 return null; 65 } 66 67 bean = def.scopeLookup(); 69 if (bean == null) { 70 bean = newBeanInstance(def.name, def.type, acquiredBeans); 72 wire(bean, acquiredBeans); 73 def.scopeRegister(bean); 74 } 75 return bean; 76 77 } 78 79 80 82 92 @SuppressWarnings ({"unchecked"}) 93 public Object create(Class type) { 94 PetiteBean ann = (PetiteBean) type.getAnnotation(PetiteBean.class); 95 if (ann != null) { 96 return getBean(ann.value().trim()); 97 } 98 Map<String , Object > acquiredBeans = new HashMap<String , Object >(); 99 Object bean = newBeanInstance(null, type, acquiredBeans); 100 wire(bean, acquiredBeans); 101 return bean; 102 } 103 104 106 109 protected Map<Class , Object []> beanCtors = new HashMap<Class , Object []>(); 110 111 122 protected Object newBeanInstance(String name, Class type, Map<String , Object > acquiredBeans) { 123 Object [] ctorData = beanCtors.get(type); 124 if (ctorData == null) { 125 ClassDescriptor cd = DefaultIntrospector.lookup(type); 126 Constructor [] allCtors = cd.getAllCtors(true); 127 boolean founded = false; 128 List<Annotation > annotations = new ArrayList<Annotation >(); 129 nextCtor: 130 for (Constructor actor : allCtors) { 131 annotations.clear(); 132 Annotation [][] paramAnnotations = actor.getParameterAnnotations(); 133 for (Annotation [] anns : paramAnnotations) { 134 boolean has = false; 135 for (Annotation a : anns) { 136 if (a.annotationType() == PetiteBeanRef.class) { 137 annotations.add(a); 138 has = true; 139 break; 140 } 141 } 142 if (has == false) { 143 continue nextCtor; 144 } 145 } 146 Annotation [] beanRefAnnotations = annotations.toArray(new Annotation [annotations.size()]); 148 ctorData = new Object [] {actor, actor.getParameterTypes(), beanRefAnnotations}; 149 Object [] previous = beanCtors.get(type); 150 boolean addOk = false; 151 if (previous == null) { 152 addOk = true; 153 } else { 154 if (((Class []) previous[1]).length == 0) { addOk = true; 156 } else if (((Class []) ctorData[1]).length == 0) { ctorData = previous; 158 continue; 159 } 160 } 161 if (addOk == true) { 162 beanCtors.put(type, ctorData); 163 } else { 164 throw new PetiteException("Type '" + type.getName() + "' contains more than one suitable constructor."); 165 } 166 founded = true; 167 } 168 if (founded == false) { 169 throw new PetiteException("Type '" + type.getName() + "' has no default or suitable constructor."); 170 } 171 } 172 173 Class [] args = (Class []) ctorData[1]; 174 if (args.length == 0) { 175 Object bean; 176 try { 177 bean = type.newInstance(); 178 } catch (Exception ex) { 179 throw new PetiteException("Unable to create new bean instance '" + type + "' using default constructor.", ex); 180 } 181 if (name != null) { 182 acquiredBeans.put(name, bean); 183 } 184 return bean; 185 } 186 187 if (name != null) { 188 acquiredBeans.put(name, Void.TYPE); } 190 Constructor c = (Constructor ) ctorData[0]; 191 Object [] argObjs = new Object [args.length]; 192 for (int i = 0; i < args.length; i++) { 193 Class arg = args[i]; 194 PetiteBeanRef pbr = (PetiteBeanRef) ((Annotation []) ctorData[2])[i]; 195 String beanRef = pbr.value(); 196 if (beanRef.length() == 0) { 197 beanRef = StringUtil.uncapitalize(arg.getSimpleName()); 198 } 199 argObjs[i] = getBean(beanRef, acquiredBeans); 200 if (argObjs[i] == null) { 201 throw new PetiteException("Reference '" + beanRef + "' not found for constructor '" + c + "'."); 202 } 203 } 204 Object bean; 205 try { 206 bean = c.newInstance(argObjs); 207 } catch (Exception ex) { 208 throw new PetiteException("Unable to create new bean instance '" + type + "' using constructor: '" + c + "'.", ex); 209 } 210 if (name != null) { 211 acquiredBeans.put(name, bean); 212 } 213 return bean; 214 } 215 216 218 221 protected Map<Class <? extends Object >, Field []> beanReferences = new HashMap<Class <? extends Object >, Field []>(); 222 223 226 public void wire(Object bean) { 227 wire(bean, new HashMap<String , Object >()); 228 } 229 230 233 protected void wire(Object bean, Map<String , Object > acquiredBeans) { 234 Class <? extends Object > type = bean.getClass(); 235 Field [] fields = beanReferences.get(type); 236 if (fields == null) { 237 ClassDescriptor cd = DefaultIntrospector.lookup(type); 238 ArrayList<Field > list = new ArrayList<Field >(); 239 Field [] allFields = cd.getAllFields(true); 240 for (Field field : allFields) { 241 PetiteBeanRef ref = field.getAnnotation(PetiteBeanRef.class); 242 if (ref == null) { 243 continue; 244 } 245 list.add(field); 246 } 247 fields = list.toArray(new Field [list.size()]); 248 beanReferences.put(type, fields); 249 } 250 251 for (Field field : fields) { 252 PetiteBeanRef ref = field.getAnnotation(PetiteBeanRef.class); 253 String refName = ref.value().trim(); 254 if (refName.length() == 0) { 255 refName = field.getName(); 256 } 257 Object value = getBean(refName, acquiredBeans); 258 if (value == null) { 259 throw new PetiteException("Reference '" + refName + "' not found for property '"+ type.toString().substring(6) + '#' + field.getName() + "'."); 260 } 261 BeanUtil.setDeclaredProperty(bean, field.getName(), value); 262 } 263 } 264 265 267 protected Class <? extends Scope> defaultScope = SingletonScope.class; 268 269 272 public Class <? extends Scope> getDefaultScope() { 273 return defaultScope; 274 } 275 276 279 public void setDefaultScope(Class <? extends Scope> defaultScope) { 280 if (defaultScope == DefaultScope.class) { 281 throw new PetiteException("Default Petite bean scope must be a concrete scope implementation."); 282 } 283 this.defaultScope = defaultScope; 284 } 285 286 288 291 protected Map<String , BeanDef> beanNames = new HashMap<String , BeanDef>(); 292 293 296 protected Map<Class <? extends Scope>, Scope> scopes = new HashMap<Class <? extends Scope>, Scope>(); 297 298 299 304 public void register(Class type) { 305 register(type, defaultScope); 306 } 307 308 313 @SuppressWarnings ({"unchecked"}) 314 public void register(Class type, Class <? extends Scope> scopeType) { 315 PetiteBean petiteBean = (PetiteBean) type.getAnnotation(PetiteBean.class); 316 String name = null; 317 if (petiteBean != null) { 318 name = petiteBean.value().trim(); 319 scopeType = petiteBean.scope(); 320 } 321 if ((name == null) || (name.length() == 0)) { 322 name = StringUtil.uncapitalize(type.getSimpleName()); 323 } 324 register(name, type, scopeType); 325 } 326 327 328 332 public void register(String name, Class type) { 333 register(name, type, defaultScope); 334 } 335 336 340 public void register(String name, Class type, Class <? extends Scope> scopeType) { 341 if (scopeType == DefaultScope.class) { 342 scopeType = defaultScope; 343 } 344 Scope scope = scopes.get(scopeType); 345 if (scope == null) { 346 try { 347 scope = scopeType.newInstance(); 348 scopes.put(scopeType, scope); 349 } catch (Exception ex) { 350 throw new PetiteException("Unable to create the Petite scope: '" + scopeType + "'.", ex); 351 } 352 } 353 if (beanNames.put(name, new BeanDef(name, type, scope)) != null) { 354 throw new PetiteException("Petite bean already registered with name '" + name + "'."); 355 } 356 } 357 358 360 365 public boolean remove(String name) { 366 return beanNames.remove(name) != null; 367 } 368 369 374 @SuppressWarnings ({"unchecked"}) 375 public boolean remove(Class type) { 376 PetiteBean petiteBean = (PetiteBean) type.getAnnotation(PetiteBean.class); 377 String name = null; 378 if (petiteBean != null) { 379 name = petiteBean.value().trim(); 380 } 381 if ((name == null) || (name.length() == 0)) { 382 name = StringUtil.uncapitalize(type.getSimpleName()); 383 } 384 return beanNames.remove(name) != null; 385 } 386 387 388 390 393 public int getTotalBeans() { 394 return beanNames.size(); 395 } 396 397 400 public int getTotalScopes() { 401 return scopes.size(); 402 } 403 404 } 405 | Popular Tags |