Author: cbrisson
Date: Tue Apr 24 15:41:21 2012
New Revision: 1329799
URL: http://svn.apache.org/viewvc?rev=1329799&view=rev
Log:
commit Candid Dauth's patch for public fields uberspector (VELOCITY-12)
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java?rev=1329799&view=auto
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
(added)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
Tue Apr 24 15:41:21 2012
@@ -0,0 +1,126 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * 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.InvocationTargetException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+/**
+ * Returns the value of a public field when executed.
+ */
+public class PublicFieldExecutor extends AbstractExecutor
+{
+ private final Introspector introspector;
+
+ /**
+ * Field to be accessed
+ */
+ private Field field = null;
+
+ /**
+ * @param log
+ * @param introspector
+ * @param clazz
+ * @param property
+ * @since 1.5
+ */
+ public PublicFieldExecutor(final Log log, final Introspector introspector,
+ final Class clazz, final String property)
+ {
+ this.log = log;
+ this.introspector = introspector;
+
+ // Don't allow passing in the empty string or null because
+ // it will either fail with a StringIndexOutOfBounds error
+ // or the introspector will get confused.
+ if (StringUtils.isNotEmpty(property))
+ {
+ discover(clazz, property);
+ }
+ }
+
+ public boolean isAlive() {
+ 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
+ */
+ protected Introspector getIntrospector()
+ {
+ return this.introspector;
+ }
+
+ /**
+ * @param clazz
+ * @param property
+ */
+ protected void discover(final Class clazz, final String property)
+ {
+ try
+ {
+ setField(introspector.getField(clazz, property));
+ }
+ /**
+ * pass through application level runtime exceptions
+ */
+ catch( RuntimeException e )
+ {
+ throw e;
+ }
+ catch(Exception e)
+ {
+ String msg = "Exception while looking for public field '" +
property;
+ log.error(msg, e);
+ throw new VelocityException(msg, e);
+ }
+ }
+
+ /**
+ * @see
org.apache.velocity.runtime.parser.node.AbstractExecutor#execute(java.lang.Object)
+ */
+ public Object execute(Object o)
+ throws IllegalAccessException, InvocationTargetException
+ {
+ return isAlive() ? getField().get(o) : null;
+ }
+}
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java?rev=1329799&view=auto
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
(added)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
Tue Apr 24 15:41:21 2012
@@ -0,0 +1,147 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * 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.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+/**
+ * Executor for setting public fields in objects
+ *
+ * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:[email protected]">Candid Dauth</a>
+ */
+public class SetPublicFieldExecutor
+ extends SetExecutor
+{
+ private final Introspector introspector;
+
+ /**
+ * Field to be accessed
+ */
+ private Field field = null;
+
+ /**
+ * @param log
+ * @param introspector
+ * @param clazz
+ * @param property
+ * @param arg
+ */
+ public SetPublicFieldExecutor(final Log log, final Introspector
introspector,
+ final Class clazz, final String property, final Object arg)
+ {
+ this.log = log;
+ this.introspector = introspector;
+
+ // Don't allow passing in the empty string or null because
+ // it will either fail with a StringIndexOutOfBounds error
+ // or the introspector will get confused.
+ if (StringUtils.isNotEmpty(property))
+ {
+ discover(clazz, property, arg);
+ }
+ }
+
+ public boolean isAlive() {
+ 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.
+ */
+ protected Introspector getIntrospector()
+ {
+ return this.introspector;
+ }
+
+ /**
+ * @param clazz
+ * @param property
+ * @param arg
+ */
+ protected void discover(final Class clazz, final String property, final
Object arg)
+ {
+ try
+ {
+ Field field = introspector.getField(clazz, property);
+ if(!Modifier.isFinal(field.getModifiers()))
+ {
+ setField(field);
+ }
+ }
+ /**
+ * pass through application level runtime exceptions
+ */
+ catch( RuntimeException e )
+ {
+ throw e;
+ }
+ catch(Exception e)
+ {
+ String msg = "Exception while looking for public field '" +
property;
+ log.error(msg, e);
+ throw new VelocityException(msg, e);
+ }
+ }
+
+ /**
+ * Execute method against context.
+ * @param o
+ * @param value
+ * @return The value of the invocation.
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public Object execute(final Object o, final Object value)
+ throws IllegalAccessException, InvocationTargetException
+ {
+ if (isAlive())
+ {
+ Object oldValue = getField().get(o);
+ getField().set(o, value);
+ return oldValue;
+ }
+ else
+ return null;
+ }
+}
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java?rev=1329799&view=auto
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
(added)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
Tue Apr 24 15:41:21 2012
@@ -0,0 +1,176 @@
+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 java.util.concurrent.ConcurrentHashMap;
+import org.apache.velocity.runtime.log.Log;
+
+/**
+ * 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 = new ConcurrentHashMap();
+ //
+ // 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);
+ }
+ }
+ }
+
+}
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
(original)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
Tue Apr 24 15:41:21 2012
@@ -19,6 +19,7 @@ package org.apache.velocity.util.introsp
* 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.L
* @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$
*/
public abstract class IntrospectorBase
@@ -106,6 +108,35 @@ public abstract class IntrospectorBase
}
/**
+ * Gets the field defined by <code>name</code>.
+ *
+ * @param c Class in which the method search is taking place
+ * @param name Name of the field being searched for
+ *
+ * @return The desired Field object.
+ * @throws IllegalArgumentException When the parameters passed in can not
be used for introspection.
+ */
+ 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.
*
* @return The internal IntrospectorCache object.
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
(original)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
Tue Apr 24 15:41:21 2012
@@ -23,6 +23,7 @@ package org.apache.velocity.util.introsp
* 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$
* @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.
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
(original)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
Tue Apr 24 15:41:21 2012
@@ -30,6 +30,7 @@ import org.apache.velocity.runtime.log.L
* 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$
* @since 1.5
*/
@@ -50,6 +51,11 @@ public final class IntrospectorCacheImpl
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
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
}
/**
+ * 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
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;
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java?rev=1329799&view=auto
==============================================================================
---
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
(added)
+++
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
Tue Apr 24 15:41:21 2012
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+package org.apache.velocity.util.introspection;
+
+import java.util.Iterator;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.runtime.parser.node.PublicFieldExecutor;
+import org.apache.velocity.runtime.parser.node.SetPublicFieldExecutor;
+import org.apache.velocity.util.introspection.UberspectImpl.VelGetterImpl;
+import org.apache.velocity.util.introspection.UberspectImpl.VelSetterImpl;
+
+/**
+ * Implementation of Uberspect to additionally provide access to public fields.
+ *
+ * @author <a href="mailto:[email protected]">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:[email protected]">Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:[email protected]">Candid Dauth</a>
+ */
+public class UberspectPublicFields implements Uberspect, UberspectLoggable
+{
+ /**
+ * Our runtime logger.
+ */
+ protected Log log;
+
+ /**
+ * the default Velocity introspector
+ */
+ protected Introspector introspector;
+
+ /**
+ * init - generates the Introspector. As the setup code
+ * makes sure that the log gets set before this is called,
+ * we can initialize the Introspector using the log object.
+ */
+ public void init()
+ {
+ introspector = new Introspector(log);
+ }
+
+ /**
+ * Sets the runtime logger - this must be called before anything
+ * else.
+ *
+ * @param log The logger instance to use.
+ * @since 1.5
+ */
+ public void setLog(Log log)
+ {
+ this.log = log;
+ }
+
+ /**
+ * Property getter
+ * @param obj
+ * @param identifier
+ * @param i
+ * @return A Velocity Getter Method.
+ * @throws Exception
+ */
+ public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ Class claz = obj.getClass();
+
+ PublicFieldExecutor executor = new PublicFieldExecutor(log,
introspector, claz, identifier);
+
+ return (executor.isAlive()) ? new VelGetterImpl(executor) : null;
+ }
+
+ /**
+ * Property setter
+ * @param obj
+ * @param identifier
+ * @param arg
+ * @param i
+ * @return A Velocity Setter method.
+ * @throws Exception
+ */
+ public VelPropertySet getPropertySet(Object obj, String identifier, Object
arg, Info i)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ Class claz = obj.getClass();
+
+ SetPublicFieldExecutor executor = new SetPublicFieldExecutor(log,
introspector, claz, identifier, arg);
+
+ return (executor.isAlive()) ? new VelSetterImpl(executor) : null;
+ }
+
+ public Iterator getIterator(Object obj, Info info)
+ {
+ return null;
+ }
+
+ public VelMethod getMethod(Object obj, String method, Object[] args, Info
info)
+ {
+ return null;
+ }
+
+}