1 52 53 package freemarker.ext.beans; 54 55 import java.beans.IndexedPropertyDescriptor ; 56 import java.beans.PropertyDescriptor ; 57 import java.lang.reflect.InvocationTargetException ; 58 import java.lang.reflect.Method ; 59 import java.util.ArrayList ; 60 import java.util.Collection ; 61 import java.util.HashMap ; 62 import java.util.List ; 63 import java.util.Map ; 64 import java.util.Set ; 65 66 import freemarker.ext.util.ModelFactory; 67 import freemarker.ext.util.WrapperTemplateModel; 68 import freemarker.log.Logger; 69 import freemarker.core.CollectionAndSequence; 70 import freemarker.template.ObjectWrapper; 71 import freemarker.template.SimpleSequence; 72 import freemarker.template.TemplateCollectionModel; 73 import freemarker.template.TemplateHashModelEx; 74 import freemarker.template.TemplateModel; 75 import freemarker.template.TemplateModelException; 76 import freemarker.template.TemplateModelIterator; 77 import freemarker.template.TemplateScalarModel; 78 79 90 91 public class BeanModel 92 implements 93 TemplateHashModelEx, WrapperTemplateModel 94 { 95 private static final Logger logger = Logger.getLogger("freemarker.beans"); 96 protected final Object object; 97 protected final BeansWrapper wrapper; 98 99 static final ModelFactory FACTORY = 100 new ModelFactory() 101 { 102 public TemplateModel create(Object object, ObjectWrapper wrapper) 103 { 104 return new BeanModel(object, (BeansWrapper)wrapper); 105 } 106 }; 107 108 private final HashMap memberMap = new HashMap (); 112 113 126 public BeanModel(Object object, BeansWrapper wrapper) 127 { 128 this.object = object; 129 this.wrapper = wrapper; 130 if (object == null) { 131 return; 132 } 133 wrapper.introspectClass(object.getClass()); 134 } 135 136 162 public TemplateModel get(String key) 163 throws 164 TemplateModelException 165 { 166 Class clazz = object.getClass(); 167 Map keyMap = wrapper.getClassKeyMap(clazz); 168 169 try 170 { 171 if(wrapper.isMethodsShadowItems()) 172 { 173 Object fd = keyMap.get(key); 174 if(fd != null) 175 { 176 return invokeThroughDescriptor(fd); 177 } 178 TemplateModel retval = invokeGenericGet(keyMap, clazz, key); 179 if(retval == null && logger.isDebugEnabled()) 180 { 181 logNoSuchKey(key, keyMap); 182 } 183 return retval; 184 } 185 else 186 { 187 TemplateModel model = invokeGenericGet(keyMap, clazz, key); 188 if(model != null) 189 { 190 return model; 191 } 192 Object fd = keyMap.get(key); 193 if(fd == null) 194 { 195 if(logger.isDebugEnabled()) 196 { 197 logNoSuchKey(key, keyMap); 198 } 199 return null; 200 } 201 return invokeThroughDescriptor(fd); 202 } 203 } 204 catch(TemplateModelException e) 205 { 206 throw e; 207 } 208 catch(Exception e) 209 { 210 throw new TemplateModelException("get(" + key + ") failed on " + 211 "instance of " + object.getClass().getName(), e); 212 } 213 } 214 215 private void logNoSuchKey(String key, Map keyMap) 216 { 217 logger.debug("Key '" + key + "' was not found on instance of " + 218 object.getClass().getName() + ". Introspection information for " + 219 "the class is: " + keyMap); 220 } 221 222 private TemplateModel invokeThroughDescriptor(Object desc) 223 throws 224 IllegalAccessException , 225 InvocationTargetException , 226 TemplateModelException 227 { 228 TemplateModel member = null; 231 synchronized(memberMap) 232 { 233 member = (TemplateModel)memberMap.get(desc); 234 } 235 236 if(member != null) 237 return member; 238 239 TemplateModel retval = null; 240 if(desc instanceof IndexedPropertyDescriptor ) 241 { 242 retval = member = 243 new SimpleMethodModel( 244 object, 245 ((IndexedPropertyDescriptor )desc).getIndexedReadMethod(), 246 wrapper); 247 } 248 else if(desc instanceof PropertyDescriptor ) 249 { 250 PropertyDescriptor pd = (PropertyDescriptor )desc; 251 retval = wrapper.invokeMethod(object, pd.getReadMethod(), null); 252 } 254 else if(desc instanceof Method ) 255 { 256 retval = member = 257 new SimpleMethodModel(object, (Method )desc, wrapper); 258 } 259 else if(desc instanceof MethodMap) 260 { 261 retval = member = 262 new OverloadedMethodModel(object, (MethodMap)desc, wrapper); 263 } 264 265 if(member != null) 267 { 268 synchronized(memberMap) 269 { 270 memberMap.put(desc, member); 271 } 272 } 273 return retval; 274 } 275 276 protected TemplateModel invokeGenericGet(Map keyMap, Class clazz, String key) 277 throws 278 IllegalAccessException , 279 InvocationTargetException , 280 TemplateModelException 281 { 282 Method genericGet = (Method )keyMap.get(BeansWrapper.GENERIC_GET_KEY); 283 if(genericGet == null) 284 return null; 285 286 return wrapper.invokeMethod(object, genericGet, new Object [] { key }); 287 } 288 289 protected TemplateModel wrap(Object obj) 290 throws TemplateModelException 291 { 292 return wrapper.getOuterIdentity().wrap(obj); 293 } 294 295 protected Object unwrap(TemplateModel model) 296 throws 297 TemplateModelException 298 { 299 return wrapper.unwrap(model); 300 } 301 302 306 public boolean isEmpty() 307 { 308 if (object instanceof String ) { 309 return ((String ) object).length() == 0; 310 } 311 if (object instanceof Collection ) { 312 return ((Collection ) object).isEmpty(); 313 } 314 if (object instanceof Map ) { 315 return ((Map ) object).isEmpty(); 316 } 317 return object == null || Boolean.FALSE.equals(object); 318 } 319 320 323 public Object getWrappedObject() 324 { 325 return object; 326 } 327 328 public int size() 329 { 330 return wrapper.keyCount(object.getClass()); 331 } 332 333 public TemplateCollectionModel keys() 334 { 335 return new CollectionAndSequence(new SimpleSequence(keySet(), wrapper)); 336 } 337 338 public TemplateCollectionModel values() throws TemplateModelException 339 { 340 List values = new ArrayList (size()); 341 TemplateModelIterator it = keys().iterator(); 342 while (it.hasNext()) { 343 String key = ((TemplateScalarModel)it.next()).getAsString(); 344 values.add(get(key)); 345 } 346 return new CollectionAndSequence(new SimpleSequence(values, wrapper)); 347 } 348 349 public String toString() { 350 return object.toString(); 351 } 352 353 359 protected Set keySet() 360 { 361 return wrapper.keySet(object.getClass()); 362 } 363 } | Popular Tags |