diff --git a/webapp/src/freemarker/ext/beans/WrapperExtractor.java b/webapp/src/freemarker/ext/beans/WrapperExtractor.java new file mode 100644 index 000000000..3fbc75f86 --- /dev/null +++ b/webapp/src/freemarker/ext/beans/WrapperExtractor.java @@ -0,0 +1,21 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package freemarker.ext.beans; + + +/** + * Class to expose template model wrapper. Used as workaround to gaps + * in the Freemarker template model API (can't get wrapper for an + * arbitrary template model object). + */ +public class WrapperExtractor { + + public static BeansWrapper getWrapper(BeanModel model) { + return model.wrapper; + } + + public static int getWrapperExposureLevel(BeanModel model) { + return model.wrapper.getExposureLevel(); + } + +} diff --git a/webapp/src/freemarker/ext/beans/WrapperUtils.java b/webapp/src/freemarker/ext/beans/WrapperUtils.java deleted file mode 100644 index da3dd33bc..000000000 --- a/webapp/src/freemarker/ext/beans/WrapperUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package freemarker.ext.beans; - -import java.lang.reflect.Member; - -/** - * Class to expose protected information about template models and their data - * and wrappers to dump methods. Used as workaround to some problems and gaps - * in the Freemarker template model API. - */ -public class WrapperUtils { - - public static BeansWrapper getWrapper(BeanModel model) { - return model.wrapper; - } - - public static int getWrapperExposureLevel(BeanModel model) { - return model.wrapper.getExposureLevel(); - } - - public static Member getMember(SimpleMethodModel model) { - return model.getMember(); - } -} diff --git a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java index 3cf9b591b..9f40bcf1a 100644 --- a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java +++ b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java @@ -28,7 +28,8 @@ import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.CollectionModel; import freemarker.ext.beans.SimpleMethodModel; import freemarker.ext.beans.StringModel; -import freemarker.ext.beans.WrapperUtils; +import freemarker.ext.beans.WrapperExtractor; +import freemarker.template.ObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; @@ -58,7 +59,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { private static final String TEMPLATE_DEFAULT = "dump.ftl"; // change to dump.ftl when old dump is removed private static final Pattern PROPERTY_NAME_PATTERN = Pattern.compile("^(get|is)\\w"); - private BeansWrapper wrapper; + private ObjectWrapper defaultWrapper; enum Key { CLASS("class"), @@ -139,6 +140,11 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { protected Map getTemplateVariableDump(String varName, Environment env) throws TemplateModelException { + defaultWrapper = env.getObjectWrapper(); + if (defaultWrapper == null) { + defaultWrapper = env.getConfiguration().getObjectWrapper(); + } + TemplateHashModel dataModel = env.getDataModel(); TemplateModel model = dataModel.get(varName); return getTemplateVariableDump(varName, model); @@ -393,15 +399,11 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { // If no arguments, invoke the method to get the result if ( methodDisplayName.endsWith("()") ) { SimpleMethodModel methodModel = (SimpleMethodModel)model.get(methodName); - Member member = WrapperUtils.getMember(methodModel); try { - if (member instanceof Method) { - Method m = (Method) member; - Object result = m.invoke(object); - BeansWrapper wrapper = getWrapper(model); - TemplateModel wrappedResult = wrapper.wrap(result); - methods.put(methodDisplayName, getDump(wrappedResult)); - } + Object result = methodModel.exec(null); + ObjectWrapper wrapper = getWrapper(model); + TemplateModel wrappedResult = wrapper.wrap(result); + methods.put(methodDisplayName, getDump(wrappedResult)); } catch (Exception e) { log.error(e, e); } @@ -426,10 +428,14 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - private BeansWrapper getWrapper(TemplateHashModelEx model) { - + private ObjectWrapper getWrapper(TemplateHashModelEx model) { + // Attempt to find the wrapper that this template model object was wrapped with. if (model instanceof BeanModel) { - return WrapperUtils.getWrapper((BeanModel)model); + return WrapperExtractor.getWrapper((BeanModel)model); + // Otherwise return the wrapper defined for the Environment or Configuration, + // if there is one. Why can't we get the wrapper for any type of TemplateModel?? + } else if (defaultWrapper != null) { + return defaultWrapper; } else { return new BeansWrapper(); } diff --git a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java index 821e9c937..98c593c4f 100644 --- a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java +++ b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java @@ -1119,6 +1119,10 @@ public class DumpDirectiveTest { return supervisor; } + public Employee boss() { + return supervisor; + } + public List getFavoriteColors() { return favoriteColors; } @@ -1151,6 +1155,10 @@ public class DumpDirectiveTest { private Map getJohnDoeExpectedDump(int exposureLevel) { Map expectedDump = new HashMap(); + + Map supervisorExpectedDump = new HashMap(); + supervisorExpectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee"); + supervisorExpectedDump.put(Key.VALUE.toString(), getJaneSmithExpectedDump(exposureLevel)); // Properties SortedMap propertiesExpectedDump = new TreeMap(); @@ -1190,10 +1198,7 @@ public class DumpDirectiveTest { marriedExpectedDump.put(Key.VALUE.toString(), true); propertiesExpectedDump.put("married", marriedExpectedDump); - Map supervisorExpectedDump = new HashMap(); - supervisorExpectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee"); - - supervisorExpectedDump.put(Key.VALUE.toString(), getJaneSmithExpectedDump(exposureLevel)); + propertiesExpectedDump.put("supervisor", supervisorExpectedDump); Map favoriteColorsExpectedDump = new HashMap(); @@ -1213,8 +1218,10 @@ public class DumpDirectiveTest { expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump); - // Methods - expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel, "Doe")); + // Methods + SortedMap methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Doe"); + methodDump.put("boss()", supervisorExpectedDump); + expectedDump.put(Key.METHODS.toString(), methodDump); return expectedDump; } @@ -1250,6 +1257,9 @@ public class DumpDirectiveTest { private Map getJaneSmithExpectedDump(int exposureLevel) { Map expectedDump = new HashMap(); + + Map supervisorExpectedDump = new HashMap(); + supervisorExpectedDump.put(Key.VALUE.toString(), Value.NULL); SortedMap propertiesExpectedDump = new TreeMap(); @@ -1289,8 +1299,6 @@ public class DumpDirectiveTest { marriedExpectedDump.put(Key.VALUE.toString(), true); propertiesExpectedDump.put("married", marriedExpectedDump); - Map supervisorExpectedDump = new HashMap(); - supervisorExpectedDump.put(Key.VALUE.toString(), Value.NULL); propertiesExpectedDump.put("supervisor", supervisorExpectedDump); Map favoriteColorsExpectedDump = new HashMap(); @@ -1310,7 +1318,9 @@ public class DumpDirectiveTest { expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump); // Methods - expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel, "Smith")); + SortedMap methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Smith"); + methodDump.put("boss()", supervisorExpectedDump); + expectedDump.put(Key.METHODS.toString(), methodDump); return expectedDump; }