The diff below, applied to CVS HEAD of FreeMarker as of 30th October 2006, will allow BeansWrapper to expose nonstatic public fields of classes, provided you call beansWrapper.setExposeFields(true) on it.
Index: src/freemarker/ext/beans/BeansWrapper.java =================================================================== RCS file: /cvsroot/freemarker/freemarker/src/freemarker/ext/beans/BeansWrapper.java,v retrieving revision 1.91.2.6 diff -u -r1.91.2.6 BeansWrapper.java --- src/freemarker/ext/beans/BeansWrapper.java 19 Apr 2006 16:18:05 -0000 1.91.2.6 +++ src/freemarker/ext/beans/BeansWrapper.java 30 Oct 2006 11:59:46 -0000 @@ -61,6 +61,7 @@ import java.io.InputStream; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -192,6 +193,7 @@ private int exposureLevel = EXPOSE_SAFE; private TemplateModel nullModel = null; private boolean methodsShadowItems = true; + private boolean exposeFields = false; private int defaultDateType = TemplateDateModel.UNKNOWN; private ObjectWrapper outerIdentity = this; @@ -302,6 +304,16 @@ return exposureLevel; } + public void setExposeFields(boolean exposeFields) + { + this.exposeFields = exposeFields; + } + + public boolean isExposeFields() + { + return exposeFields; + } + /** * Sets whether methods shadow items in beans. When true (this is the * default value), <code>${object.name}</code> will first try to locate @@ -824,6 +836,18 @@ private Map populateClassMapWithBeanInfo(Class clazz) { Map classMap = new HashMap(); + if(exposeFields) + { + Field[] fields = clazz.getFields(); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if((field.getModifiers() & Modifier.STATIC) == 0) + { + classMap.put(field.getName(), field); + } + } + } Map accessibleMethods = discoverAccessibleMethods(clazz); Method genericGet = (Method)accessibleMethods.get(MethodSignature.GET_STRING_SIGNATURE); if(genericGet == null) Index: src/freemarker/ext/beans/BeanModel.java =================================================================== RCS file: /cvsroot/freemarker/freemarker/src/freemarker/ext/beans/BeanModel.java,v retrieving revision 1.49.2.3 diff -u -r1.49.2.3 BeanModel.java --- src/freemarker/ext/beans/BeanModel.java 19 Apr 2006 16:20:54 -0000 1.49.2.3 +++ src/freemarker/ext/beans/BeanModel.java 30 Oct 2006 11:59:44 -0000 @@ -54,6 +54,7 @@ import java.beans.IndexedPropertyDescriptor; import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -64,7 +65,6 @@ import java.util.Set; import freemarker.core.CollectionAndSequence; -import freemarker.core.Environment; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; import freemarker.log.Logger; @@ -272,6 +272,11 @@ retval = wrapper.invokeMethod(object, pd.getReadMethod(), null); // (member == null) condition remains, as we don't cache these } + else if(desc instanceof Field) + { + retval = wrapper.wrap(((Field)desc).get(object)); + // (member == null) condition remains, as we don't cache these + } else if(desc instanceof Method) { Method method = (Method)desc;