Guest User

VELOCITY-12.patch

a guest
Mar 30th, 2011
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 15.81 KB | None | 0 0
  1. diff --git a/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java b/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
  2. index 8c78228..ba5d25e 100644
  3. --- a/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
  4. +++ b/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
  5. @@ -19,6 +19,7 @@ package org.apache.velocity.runtime.parser.node;
  6.   * under the License.    
  7.   */
  8.  
  9. +import java.lang.reflect.Field;
  10.  import java.lang.reflect.InvocationTargetException;
  11.  
  12.  import org.apache.commons.lang.StringUtils;
  13. @@ -36,6 +37,11 @@ public class PropertyExecutor extends AbstractExecutor
  14.      private final Introspector introspector;
  15.  
  16.      /**
  17. +     * Field to be accessed in case no getter method was found.
  18. +     */
  19. +    private Field field = null;
  20. +
  21. +    /**
  22.       * @param log
  23.       * @param introspector
  24.       * @param clazz
  25. @@ -70,6 +76,29 @@ public class PropertyExecutor extends AbstractExecutor
  26.          this(new RuntimeLoggerLog(r), introspector, clazz, property);
  27.      }
  28.  
  29. +    public boolean isAlive() {
  30. +        if (super.isAlive())
  31. +            return true;
  32. +
  33. +        return getField() != null;
  34. +    }
  35. +
  36. +    /**
  37. +     * @return The current field.
  38. +     */
  39. +    public Field getField()
  40. +    {
  41. +        return field;
  42. +    }
  43. +
  44. +    /**
  45. +     * @param field
  46. +     */
  47. +    protected void setField(final Field field)
  48. +    {
  49. +        this.field = field;
  50. +    }
  51. +
  52.      /**
  53.       * @return The current introspector.
  54.       * @since 1.5
  55. @@ -116,6 +145,15 @@ public class PropertyExecutor extends AbstractExecutor
  56.                  }
  57.  
  58.                  setMethod(introspector.getMethod(clazz, sb.toString(), params));
  59. +
  60. +                if (!isAlive())
  61. +                {
  62. +                    /*
  63. +                     * Check for existing public property
  64. +                     */
  65. +
  66. +                    setField(introspector.getField(clazz, property));
  67. +                }
  68.              }
  69.          }
  70.          /**
  71. @@ -139,6 +177,17 @@ public class PropertyExecutor extends AbstractExecutor
  72.      public Object execute(Object o)
  73.          throws IllegalAccessException,  InvocationTargetException
  74.      {
  75. -        return isAlive() ? getMethod().invoke(o, ((Object []) null)) : null;
  76. +        if (!isAlive())
  77. +        {
  78. +            return null;
  79. +        }
  80. +        else if (getMethod() != null)
  81. +        {
  82. +            return getMethod().invoke(o, ((Object []) null));
  83. +        }
  84. +        else
  85. +        {
  86. +            return getField().get(o);
  87. +        }
  88.      }
  89.  }
  90. diff --git a/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java b/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java
  91. new file mode 100644
  92. index 0000000..5597ebe
  93. --- /dev/null
  94. +++ b/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java
  95. @@ -0,0 +1,175 @@
  96. +package org.apache.velocity.util.introspection;
  97. +
  98. +/*
  99. + * Licensed to the Apache Software Foundation (ASF) under one
  100. + * or more contributor license agreements.  See the NOTICE file
  101. + * distributed with this work for additional information
  102. + * regarding copyright ownership.  The ASF licenses this file
  103. + * to you under the Apache License, Version 2.0 (the
  104. + * "License"); you may not use this file except in compliance
  105. + * with the License.  You may obtain a copy of the License at
  106. + *
  107. + *   http://www.apache.org/licenses/LICENSE-2.0
  108. + *
  109. + * Unless required by applicable law or agreed to in writing,
  110. + * software distributed under the License is distributed on an
  111. + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  112. + * KIND, either express or implied.  See the License for the
  113. + * specific language governing permissions and limitations
  114. + * under the License.
  115. + */
  116. +
  117. +import java.lang.reflect.Field;
  118. +import java.lang.reflect.Modifier;
  119. +import java.util.Map;
  120. +import org.apache.velocity.runtime.log.Log;
  121. +import org.apache.velocity.util.MapFactory;
  122. +
  123. +/**
  124. + * A cache of introspection information for a specific class instance.
  125. + * Keys {@link java.lang.reflect.Field} objects by the field names.
  126. + *
  127. + * @author <a href="mailto:[email protected]">Jason van Zyl</a>
  128. + * @author <a href="mailto:[email protected]">Bob McWhirter</a>
  129. + * @author <a href="mailto:[email protected]">Attila Szegedi</a>
  130. + * @author <a href="mailto:[email protected]">Geir Magnusson Jr.</a>
  131. + * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
  132. + * @author Nathan Bubna
  133. + * @author <a href="mailto:[email protected]">Candid Dauth</a>
  134. + */
  135. +public class ClassFieldMap
  136. +{
  137. +    /** Set true if you want to debug the reflection code */
  138. +    private static final boolean debugReflection = false;
  139. +
  140. +    /** Class logger */
  141. +    private final Log log;
  142. +
  143. +    /**
  144. +     * Class passed into the constructor used to as
  145. +     * the basis for the Field map.
  146. +     */
  147. +    private final Class clazz;
  148. +
  149. +    /**
  150. +     * String --&gt; Field map, the key is the field name
  151. +     */
  152. +    private final Map fieldCache;
  153. +
  154. +    /**
  155. +     * Standard constructor
  156. +     * @param clazz The class for which this ClassMap gets constructed.
  157. +     */
  158. +    public ClassFieldMap(final Class clazz, final Log log)
  159. +    {
  160. +        this.clazz = clazz;
  161. +        this.log = log;
  162. +
  163. +        if (debugReflection && log.isDebugEnabled())
  164. +        {
  165. +            log.debug("=================================================================");
  166. +            log.debug("== Class: " + clazz);
  167. +        }
  168. +
  169. +        fieldCache = createFieldCache();
  170. +
  171. +        if (debugReflection && log.isDebugEnabled())
  172. +        {
  173. +            log.debug("=================================================================");
  174. +        }
  175. +    }
  176. +
  177. +    /**
  178. +     * Returns the class object whose fields are cached by this map.
  179. +     *
  180. +     * @return The class object whose fields are cached by this map.
  181. +     */
  182. +    public Class getCachedClass()
  183. +    {
  184. +        return clazz;
  185. +    }
  186. +
  187. +    /**
  188. +     * Find a Field using the field name.
  189. +     *
  190. +     * @param name The field name to look up.
  191. +     * @return A Field object representing the field to invoke or null.
  192. +     */
  193. +    public Field findField(final String name)
  194. +    {
  195. +        return (Field)fieldCache.get(name);
  196. +    }
  197. +
  198. +    /**
  199. +     * Populate the Map of direct hits. These
  200. +     * are taken from all the public fields
  201. +     * that our class, its parents and their implemented interfaces provide.
  202. +     */
  203. +    private Map createFieldCache()
  204. +    {
  205. +        Map fieldCache = MapFactory.create(false);
  206. +   //
  207. +   // Looks through all elements in the class hierarchy.
  208. +   //
  209. +   // We ignore all SecurityExceptions that might happen due to SecurityManager restrictions (prominently
  210. +   // hit with Tomcat 5.5).
  211. +        // Ah, the miracles of Java for(;;) ...
  212. +        for (Class classToReflect = getCachedClass(); classToReflect != null ; classToReflect = classToReflect.getSuperclass())
  213. +        {
  214. +            if (Modifier.isPublic(classToReflect.getModifiers()))
  215. +            {
  216. +                populateFieldCacheWith(fieldCache, classToReflect);
  217. +            }
  218. +            Class [] interfaces = classToReflect.getInterfaces();
  219. +            for (int i = 0; i < interfaces.length; i++)
  220. +            {
  221. +                populateFieldCacheWithInterface(fieldCache, interfaces[i]);
  222. +            }
  223. +        }
  224. +        // return the already initialized cache
  225. +        return fieldCache;
  226. +    }
  227. +
  228. +    /* recurses up interface heirarchy to get all super interfaces (VELOCITY-689) */
  229. +    private void populateFieldCacheWithInterface(Map fieldCache, Class iface)
  230. +    {
  231. +        if (Modifier.isPublic(iface.getModifiers()))
  232. +        {
  233. +            populateFieldCacheWith(fieldCache, iface);
  234. +        }
  235. +        Class[] supers = iface.getInterfaces();
  236. +        for (int i=0; i < supers.length; i++)
  237. +        {
  238. +            populateFieldCacheWithInterface(fieldCache, supers[i]);
  239. +        }
  240. +    }
  241. +
  242. +    private void populateFieldCacheWith(Map fieldCache, Class classToReflect)
  243. +    {
  244. +        if (debugReflection && log.isDebugEnabled())
  245. +        {
  246. +            log.debug("Reflecting " + classToReflect);
  247. +        }
  248. +
  249. +        try
  250. +        {
  251. +            Field[] fields = classToReflect.getDeclaredFields();
  252. +            for (int i = 0; i < fields.length; i++)
  253. +            {
  254. +                int modifiers = fields[i].getModifiers();
  255. +                if (Modifier.isPublic(modifiers))
  256. +                {
  257. +                    fieldCache.put(fields[i].getName(), fields[i]);
  258. +                }
  259. +            }
  260. +        }
  261. +        catch (SecurityException se) // Everybody feels better with...
  262. +        {
  263. +            if (log.isDebugEnabled())
  264. +            {
  265. +                log.debug("While accessing fields of " + classToReflect + ": ", se);
  266. +            }
  267. +        }
  268. +    }
  269. +
  270. +}
  271. diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java b/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
  272. index db6031f..aab217b 100644
  273. --- a/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
  274. +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
  275. @@ -19,6 +19,7 @@ package org.apache.velocity.util.introspection;
  276.   * under the License.    
  277.   */
  278.  
  279. +import java.lang.reflect.Field;
  280.  import java.lang.reflect.Method;
  281.  
  282.  import org.apache.velocity.runtime.log.Log;
  283. @@ -49,6 +50,7 @@ import org.apache.velocity.runtime.log.Log;
  284.   * @author <a href="mailto:[email protected]">Attila Szegedi</a>
  285.   * @author <a href="mailto:[email protected]">Paulo Gaspar</a>
  286.   * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
  287. + * @author <a href="mailto:[email protected]">Candid Dauth</a>
  288.   * @version $Id: IntrospectorBase.java 685685 2008-08-13 21:43:27Z nbubna $
  289.   */
  290.  public abstract class IntrospectorBase
  291. @@ -105,6 +107,26 @@ public abstract class IntrospectorBase
  292.          return classMap.findMethod(name, params);
  293.      }
  294.  
  295. +    public Field getField(final Class c, final String name)
  296. +            throws IllegalArgumentException
  297. +    {
  298. +        if (c == null)
  299. +        {
  300. +            throw new IllegalArgumentException("class object is null!");
  301. +        }
  302. +
  303. +        IntrospectorCache ic = getIntrospectorCache();
  304. +
  305. +        ClassFieldMap classFieldMap = ic.getFieldMap(c);
  306. +        if (classFieldMap == null)
  307. +        {
  308. +            ic.put(c);
  309. +            classFieldMap = ic.getFieldMap(c);
  310. +        }
  311. +
  312. +        return classFieldMap.findField(name);
  313. +    }
  314. +
  315.      /**
  316.       * Return the internal IntrospectorCache object.
  317.       *
  318. diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java b/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
  319. index 3b70728..a730996 100644
  320. --- a/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
  321. +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
  322. @@ -23,6 +23,7 @@ package org.apache.velocity.util.introspection;
  323.   * The introspector cache API definition.
  324.   *
  325.   * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
  326. + * @author <a href="mailto:[email protected]">Candid Dauth</a>
  327.   * @version $Id: IntrospectorCache.java 685685 2008-08-13 21:43:27Z nbubna $
  328.   * @since 1.5
  329.   */
  330. @@ -44,6 +45,16 @@ public interface IntrospectorCache {
  331.      ClassMap get(Class c);
  332.  
  333.      /**
  334. +     * Lookup a given Class object in the cache. If it does not exist,
  335. +     * check whether this is due to a class change and purge the caches
  336. +     * eventually.
  337. +     *
  338. +     * @param c The class to look up.
  339. +     * @return A ClassFieldMap object or null if it does not exist in the cache.
  340. +     */
  341. +    ClassFieldMap getFieldMap(final Class c);
  342. +
  343. +    /**
  344.       * Creates a class map for specific class and registers it in the
  345.       * cache.  Also adds the qualified name to the name-&gt;class map
  346.       * for later Classloader change detection.
  347. diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java b/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
  348. index 1dbe9cd..6b7ebab 100644
  349. --- a/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
  350. +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
  351. @@ -30,6 +30,7 @@ import org.apache.velocity.runtime.log.Log;
  352.   * This is the internal introspector cache implementation.
  353.   *
  354.   * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
  355. + * @author <a href="mailto:[email protected]">Candid Dauth</a>
  356.   * @version $Id: IntrospectorCacheImpl.java 898032 2010-01-11 19:51:03Z nbubna $
  357.   * @since 1.5
  358.   */
  359. @@ -50,6 +51,11 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
  360.      private final Map classMapCache = new HashMap();
  361.  
  362.      /**
  363. +     * Holds the field maps for the classes we know about. Map: Class --&gt; ClassFieldMap object.
  364. +     */
  365. +    private final Map classFieldMapCache = new HashMap();
  366. +
  367. +    /**
  368.       * Keep the names of the classes in another map. This is needed for a multi-classloader environment where it is possible
  369.       * to have Class 'Foo' loaded by a classloader and then get asked to introspect on 'Foo' from another class loader. While these
  370.       * two Class objects have the same name, a <code>classMethodMaps.get(Foo.class)</code> will return null. For that case, we
  371. @@ -73,13 +79,14 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
  372.          synchronized (classMapCache)
  373.          {
  374.              classMapCache.clear();
  375. +            classFieldMapCache.clear();
  376.              classNameCache.clear();
  377.              log.debug(CACHEDUMP_MSG);
  378.          }
  379.      }
  380.  
  381.      /**
  382. -     * Lookup a given Class object in the cache. If it does not exist,
  383. +     * Lookup a given Class object in the cache. If it does not exist,
  384.       * check whether this is due to a class change and purge the caches
  385.       * eventually.
  386.       *
  387. @@ -114,6 +121,41 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
  388.      }
  389.  
  390.      /**
  391. +     * Lookup a given Class object in the cache. If it does not exist,
  392. +     * check whether this is due to a class change and purge the caches
  393. +     * eventually.
  394. +     *
  395. +     * @param c The class to look up.
  396. +     * @return A ClassFieldMap object or null if it does not exist in the cache.
  397. +     */
  398. +    public ClassFieldMap getFieldMap(final Class c)
  399. +    {
  400. +        if (c == null)
  401. +        {
  402. +            throw new IllegalArgumentException("class is null!");
  403. +        }
  404. +
  405. +        ClassFieldMap classFieldMap = (ClassFieldMap)classFieldMapCache.get(c);
  406. +        if (classFieldMap == null)
  407. +        {
  408. +            /*
  409. +             * check to see if we have it by name.
  410. +             * if so, then we have an object with the same
  411. +             * name but loaded through a different class loader.
  412. +             * In that case, we will just dump the cache to be sure.
  413. +             */
  414. +            synchronized (classMapCache)
  415. +            {
  416. +                if (classNameCache.contains(c.getName()))
  417. +                {
  418. +                    clear();
  419. +                }
  420. +            }
  421. +        }
  422. +        return classFieldMap;
  423. +    }
  424. +
  425. +    /**
  426.       * Creates a class map for specific class and registers it in the
  427.       * cache.  Also adds the qualified name to the name-&gt;class map
  428.       * for later Classloader change detection.
  429. @@ -124,9 +166,11 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
  430.      public ClassMap put(final Class c)
  431.      {
  432.          final ClassMap classMap = new ClassMap(c, log);
  433. +        final ClassFieldMap classFieldMap = new ClassFieldMap(c, log);
  434.          synchronized (classMapCache)
  435.          {
  436.              classMapCache.put(c, classMap);
  437. +            classFieldMapCache.put(c, classFieldMap);
  438.              classNameCache.add(c.getName());
  439.          }
  440.          return classMap;
Advertisement
Add Comment
Please, Sign In to add comment