Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java b/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
- index 8c78228..ba5d25e 100644
- --- a/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
- +++ b/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
- @@ -19,6 +19,7 @@ package org.apache.velocity.runtime.parser.node;
- * under the License.
- */
- +import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import org.apache.commons.lang.StringUtils;
- @@ -36,6 +37,11 @@ public class PropertyExecutor extends AbstractExecutor
- private final Introspector introspector;
- /**
- + * Field to be accessed in case no getter method was found.
- + */
- + private Field field = null;
- +
- + /**
- * @param log
- * @param introspector
- * @param clazz
- @@ -70,6 +76,29 @@ public class PropertyExecutor extends AbstractExecutor
- this(new RuntimeLoggerLog(r), introspector, clazz, property);
- }
- + public boolean isAlive() {
- + if (super.isAlive())
- + return true;
- +
- + return getField() != null;
- + }
- +
- + /**
- + * @return The current field.
- + */
- + public Field getField()
- + {
- + return field;
- + }
- +
- + /**
- + * @param field
- + */
- + protected void setField(final Field field)
- + {
- + this.field = field;
- + }
- +
- /**
- * @return The current introspector.
- * @since 1.5
- @@ -116,6 +145,15 @@ public class PropertyExecutor extends AbstractExecutor
- }
- setMethod(introspector.getMethod(clazz, sb.toString(), params));
- +
- + if (!isAlive())
- + {
- + /*
- + * Check for existing public property
- + */
- +
- + setField(introspector.getField(clazz, property));
- + }
- }
- }
- /**
- @@ -139,6 +177,17 @@ public class PropertyExecutor extends AbstractExecutor
- public Object execute(Object o)
- throws IllegalAccessException, InvocationTargetException
- {
- - return isAlive() ? getMethod().invoke(o, ((Object []) null)) : null;
- + if (!isAlive())
- + {
- + return null;
- + }
- + else if (getMethod() != null)
- + {
- + return getMethod().invoke(o, ((Object []) null));
- + }
- + else
- + {
- + return getField().get(o);
- + }
- }
- }
- diff --git a/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java b/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java
- new file mode 100644
- index 0000000..5597ebe
- --- /dev/null
- +++ b/src/java/org/apache/velocity/util/introspection/ClassFieldMap.java
- @@ -0,0 +1,175 @@
- +package org.apache.velocity.util.introspection;
- +
- +/*
- + * Licensed to the Apache Software Foundation (ASF) under one
- + * or more contributor license agreements. See the NOTICE file
- + * distributed with this work for additional information
- + * regarding copyright ownership. The ASF licenses this file
- + * to you under the Apache License, Version 2.0 (the
- + * "License"); you may not use this file except in compliance
- + * with the License. You may obtain a copy of the License at
- + *
- + * http://www.apache.org/licenses/LICENSE-2.0
- + *
- + * Unless required by applicable law or agreed to in writing,
- + * software distributed under the License is distributed on an
- + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- + * KIND, either express or implied. See the License for the
- + * specific language governing permissions and limitations
- + * under the License.
- + */
- +
- +import java.lang.reflect.Field;
- +import java.lang.reflect.Modifier;
- +import java.util.Map;
- +import org.apache.velocity.runtime.log.Log;
- +import org.apache.velocity.util.MapFactory;
- +
- +/**
- + * A cache of introspection information for a specific class instance.
- + * Keys {@link java.lang.reflect.Field} objects by the field names.
- + *
- + * @author <a href="mailto:[email protected]">Jason van Zyl</a>
- + * @author <a href="mailto:[email protected]">Bob McWhirter</a>
- + * @author <a href="mailto:[email protected]">Attila Szegedi</a>
- + * @author <a href="mailto:[email protected]">Geir Magnusson Jr.</a>
- + * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
- + * @author Nathan Bubna
- + * @author <a href="mailto:[email protected]">Candid Dauth</a>
- + */
- +public class ClassFieldMap
- +{
- + /** Set true if you want to debug the reflection code */
- + private static final boolean debugReflection = false;
- +
- + /** Class logger */
- + private final Log log;
- +
- + /**
- + * Class passed into the constructor used to as
- + * the basis for the Field map.
- + */
- + private final Class clazz;
- +
- + /**
- + * String --> Field map, the key is the field name
- + */
- + private final Map fieldCache;
- +
- + /**
- + * Standard constructor
- + * @param clazz The class for which this ClassMap gets constructed.
- + */
- + public ClassFieldMap(final Class clazz, final Log log)
- + {
- + this.clazz = clazz;
- + this.log = log;
- +
- + if (debugReflection && log.isDebugEnabled())
- + {
- + log.debug("=================================================================");
- + log.debug("== Class: " + clazz);
- + }
- +
- + fieldCache = createFieldCache();
- +
- + if (debugReflection && log.isDebugEnabled())
- + {
- + log.debug("=================================================================");
- + }
- + }
- +
- + /**
- + * Returns the class object whose fields are cached by this map.
- + *
- + * @return The class object whose fields are cached by this map.
- + */
- + public Class getCachedClass()
- + {
- + return clazz;
- + }
- +
- + /**
- + * Find a Field using the field name.
- + *
- + * @param name The field name to look up.
- + * @return A Field object representing the field to invoke or null.
- + */
- + public Field findField(final String name)
- + {
- + return (Field)fieldCache.get(name);
- + }
- +
- + /**
- + * Populate the Map of direct hits. These
- + * are taken from all the public fields
- + * that our class, its parents and their implemented interfaces provide.
- + */
- + private Map createFieldCache()
- + {
- + Map fieldCache = MapFactory.create(false);
- + //
- + // Looks through all elements in the class hierarchy.
- + //
- + // We ignore all SecurityExceptions that might happen due to SecurityManager restrictions (prominently
- + // hit with Tomcat 5.5).
- + // Ah, the miracles of Java for(;;) ...
- + for (Class classToReflect = getCachedClass(); classToReflect != null ; classToReflect = classToReflect.getSuperclass())
- + {
- + if (Modifier.isPublic(classToReflect.getModifiers()))
- + {
- + populateFieldCacheWith(fieldCache, classToReflect);
- + }
- + Class [] interfaces = classToReflect.getInterfaces();
- + for (int i = 0; i < interfaces.length; i++)
- + {
- + populateFieldCacheWithInterface(fieldCache, interfaces[i]);
- + }
- + }
- + // return the already initialized cache
- + return fieldCache;
- + }
- +
- + /* recurses up interface heirarchy to get all super interfaces (VELOCITY-689) */
- + private void populateFieldCacheWithInterface(Map fieldCache, Class iface)
- + {
- + if (Modifier.isPublic(iface.getModifiers()))
- + {
- + populateFieldCacheWith(fieldCache, iface);
- + }
- + Class[] supers = iface.getInterfaces();
- + for (int i=0; i < supers.length; i++)
- + {
- + populateFieldCacheWithInterface(fieldCache, supers[i]);
- + }
- + }
- +
- + private void populateFieldCacheWith(Map fieldCache, Class classToReflect)
- + {
- + if (debugReflection && log.isDebugEnabled())
- + {
- + log.debug("Reflecting " + classToReflect);
- + }
- +
- + try
- + {
- + Field[] fields = classToReflect.getDeclaredFields();
- + for (int i = 0; i < fields.length; i++)
- + {
- + int modifiers = fields[i].getModifiers();
- + if (Modifier.isPublic(modifiers))
- + {
- + fieldCache.put(fields[i].getName(), fields[i]);
- + }
- + }
- + }
- + catch (SecurityException se) // Everybody feels better with...
- + {
- + if (log.isDebugEnabled())
- + {
- + log.debug("While accessing fields of " + classToReflect + ": ", se);
- + }
- + }
- + }
- +
- +}
- diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java b/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
- index db6031f..aab217b 100644
- --- a/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
- +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
- @@ -19,6 +19,7 @@ package org.apache.velocity.util.introspection;
- * under the License.
- */
- +import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import org.apache.velocity.runtime.log.Log;
- @@ -49,6 +50,7 @@ import org.apache.velocity.runtime.log.Log;
- * @author <a href="mailto:[email protected]">Attila Szegedi</a>
- * @author <a href="mailto:[email protected]">Paulo Gaspar</a>
- * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
- + * @author <a href="mailto:[email protected]">Candid Dauth</a>
- * @version $Id: IntrospectorBase.java 685685 2008-08-13 21:43:27Z nbubna $
- */
- public abstract class IntrospectorBase
- @@ -105,6 +107,26 @@ public abstract class IntrospectorBase
- return classMap.findMethod(name, params);
- }
- + public Field getField(final Class c, final String name)
- + throws IllegalArgumentException
- + {
- + if (c == null)
- + {
- + throw new IllegalArgumentException("class object is null!");
- + }
- +
- + IntrospectorCache ic = getIntrospectorCache();
- +
- + ClassFieldMap classFieldMap = ic.getFieldMap(c);
- + if (classFieldMap == null)
- + {
- + ic.put(c);
- + classFieldMap = ic.getFieldMap(c);
- + }
- +
- + return classFieldMap.findField(name);
- + }
- +
- /**
- * Return the internal IntrospectorCache object.
- *
- diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java b/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
- index 3b70728..a730996 100644
- --- a/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
- +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
- @@ -23,6 +23,7 @@ package org.apache.velocity.util.introspection;
- * The introspector cache API definition.
- *
- * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
- + * @author <a href="mailto:[email protected]">Candid Dauth</a>
- * @version $Id: IntrospectorCache.java 685685 2008-08-13 21:43:27Z nbubna $
- * @since 1.5
- */
- @@ -44,6 +45,16 @@ public interface IntrospectorCache {
- ClassMap get(Class c);
- /**
- + * Lookup a given Class object in the cache. If it does not exist,
- + * check whether this is due to a class change and purge the caches
- + * eventually.
- + *
- + * @param c The class to look up.
- + * @return A ClassFieldMap object or null if it does not exist in the cache.
- + */
- + ClassFieldMap getFieldMap(final Class c);
- +
- + /**
- * Creates a class map for specific class and registers it in the
- * cache. Also adds the qualified name to the name->class map
- * for later Classloader change detection.
- diff --git a/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java b/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
- index 1dbe9cd..6b7ebab 100644
- --- a/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
- +++ b/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
- @@ -30,6 +30,7 @@ import org.apache.velocity.runtime.log.Log;
- * This is the internal introspector cache implementation.
- *
- * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
- + * @author <a href="mailto:[email protected]">Candid Dauth</a>
- * @version $Id: IntrospectorCacheImpl.java 898032 2010-01-11 19:51:03Z nbubna $
- * @since 1.5
- */
- @@ -50,6 +51,11 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
- private final Map classMapCache = new HashMap();
- /**
- + * Holds the field maps for the classes we know about. Map: Class --> ClassFieldMap object.
- + */
- + private final Map classFieldMapCache = new HashMap();
- +
- + /**
- * Keep the names of the classes in another map. This is needed for a multi-classloader environment where it is possible
- * to have Class 'Foo' loaded by a classloader and then get asked to introspect on 'Foo' from another class loader. While these
- * two Class objects have the same name, a <code>classMethodMaps.get(Foo.class)</code> will return null. For that case, we
- @@ -73,13 +79,14 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
- synchronized (classMapCache)
- {
- classMapCache.clear();
- + classFieldMapCache.clear();
- classNameCache.clear();
- log.debug(CACHEDUMP_MSG);
- }
- }
- /**
- - * Lookup a given Class object in the cache. If it does not exist,
- + * Lookup a given Class object in the cache. If it does not exist,
- * check whether this is due to a class change and purge the caches
- * eventually.
- *
- @@ -114,6 +121,41 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
- }
- /**
- + * Lookup a given Class object in the cache. If it does not exist,
- + * check whether this is due to a class change and purge the caches
- + * eventually.
- + *
- + * @param c The class to look up.
- + * @return A ClassFieldMap object or null if it does not exist in the cache.
- + */
- + public ClassFieldMap getFieldMap(final Class c)
- + {
- + if (c == null)
- + {
- + throw new IllegalArgumentException("class is null!");
- + }
- +
- + ClassFieldMap classFieldMap = (ClassFieldMap)classFieldMapCache.get(c);
- + if (classFieldMap == null)
- + {
- + /*
- + * check to see if we have it by name.
- + * if so, then we have an object with the same
- + * name but loaded through a different class loader.
- + * In that case, we will just dump the cache to be sure.
- + */
- + synchronized (classMapCache)
- + {
- + if (classNameCache.contains(c.getName()))
- + {
- + clear();
- + }
- + }
- + }
- + return classFieldMap;
- + }
- +
- + /**
- * Creates a class map for specific class and registers it in the
- * cache. Also adds the qualified name to the name->class map
- * for later Classloader change detection.
- @@ -124,9 +166,11 @@ public final class IntrospectorCacheImpl implements IntrospectorCache
- public ClassMap put(final Class c)
- {
- final ClassMap classMap = new ClassMap(c, log);
- + final ClassFieldMap classFieldMap = new ClassFieldMap(c, log);
- synchronized (classMapCache)
- {
- classMapCache.put(c, classMap);
- + classFieldMapCache.put(c, classFieldMap);
- classNameCache.add(c.getName());
- }
- return classMap;
Advertisement
Add Comment
Please, Sign In to add comment