NIHVIVO-3087 Improve handling of method invocation in argumentless method dump. Add unit test for this case.
This commit is contained in:
parent
4229e04a02
commit
092f6ed4d8
4 changed files with 59 additions and 47 deletions
21
webapp/src/freemarker/ext/beans/WrapperExtractor.java
Normal file
21
webapp/src/freemarker/ext/beans/WrapperExtractor.java
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,7 +28,8 @@ import freemarker.ext.beans.BeansWrapper;
|
||||||
import freemarker.ext.beans.CollectionModel;
|
import freemarker.ext.beans.CollectionModel;
|
||||||
import freemarker.ext.beans.SimpleMethodModel;
|
import freemarker.ext.beans.SimpleMethodModel;
|
||||||
import freemarker.ext.beans.StringModel;
|
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.Template;
|
||||||
import freemarker.template.TemplateBooleanModel;
|
import freemarker.template.TemplateBooleanModel;
|
||||||
import freemarker.template.TemplateCollectionModel;
|
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 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 static final Pattern PROPERTY_NAME_PATTERN = Pattern.compile("^(get|is)\\w");
|
||||||
|
|
||||||
private BeansWrapper wrapper;
|
private ObjectWrapper defaultWrapper;
|
||||||
|
|
||||||
enum Key {
|
enum Key {
|
||||||
CLASS("class"),
|
CLASS("class"),
|
||||||
|
@ -139,6 +140,11 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
protected Map<String, Object> getTemplateVariableDump(String varName, Environment env)
|
protected Map<String, Object> getTemplateVariableDump(String varName, Environment env)
|
||||||
throws TemplateModelException {
|
throws TemplateModelException {
|
||||||
|
|
||||||
|
defaultWrapper = env.getObjectWrapper();
|
||||||
|
if (defaultWrapper == null) {
|
||||||
|
defaultWrapper = env.getConfiguration().getObjectWrapper();
|
||||||
|
}
|
||||||
|
|
||||||
TemplateHashModel dataModel = env.getDataModel();
|
TemplateHashModel dataModel = env.getDataModel();
|
||||||
TemplateModel model = dataModel.get(varName);
|
TemplateModel model = dataModel.get(varName);
|
||||||
return getTemplateVariableDump(varName, model);
|
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 no arguments, invoke the method to get the result
|
||||||
if ( methodDisplayName.endsWith("()") ) {
|
if ( methodDisplayName.endsWith("()") ) {
|
||||||
SimpleMethodModel methodModel = (SimpleMethodModel)model.get(methodName);
|
SimpleMethodModel methodModel = (SimpleMethodModel)model.get(methodName);
|
||||||
Member member = WrapperUtils.getMember(methodModel);
|
|
||||||
try {
|
try {
|
||||||
if (member instanceof Method) {
|
Object result = methodModel.exec(null);
|
||||||
Method m = (Method) member;
|
ObjectWrapper wrapper = getWrapper(model);
|
||||||
Object result = m.invoke(object);
|
TemplateModel wrappedResult = wrapper.wrap(result);
|
||||||
BeansWrapper wrapper = getWrapper(model);
|
methods.put(methodDisplayName, getDump(wrappedResult));
|
||||||
TemplateModel wrappedResult = wrapper.wrap(result);
|
|
||||||
methods.put(methodDisplayName, getDump(wrappedResult));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e, e);
|
log.error(e, e);
|
||||||
}
|
}
|
||||||
|
@ -426,10 +428,14 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
return map;
|
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) {
|
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 {
|
} else {
|
||||||
return new BeansWrapper();
|
return new BeansWrapper();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1119,6 +1119,10 @@ public class DumpDirectiveTest {
|
||||||
return supervisor;
|
return supervisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Employee boss() {
|
||||||
|
return supervisor;
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> getFavoriteColors() {
|
public List<String> getFavoriteColors() {
|
||||||
return favoriteColors;
|
return favoriteColors;
|
||||||
}
|
}
|
||||||
|
@ -1151,6 +1155,10 @@ public class DumpDirectiveTest {
|
||||||
private Map<String, Object> getJohnDoeExpectedDump(int exposureLevel) {
|
private Map<String, Object> getJohnDoeExpectedDump(int exposureLevel) {
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
|
||||||
|
supervisorExpectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
||||||
|
supervisorExpectedDump.put(Key.VALUE.toString(), getJaneSmithExpectedDump(exposureLevel));
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();
|
SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();
|
||||||
|
@ -1190,10 +1198,7 @@ public class DumpDirectiveTest {
|
||||||
marriedExpectedDump.put(Key.VALUE.toString(), true);
|
marriedExpectedDump.put(Key.VALUE.toString(), true);
|
||||||
propertiesExpectedDump.put("married", marriedExpectedDump);
|
propertiesExpectedDump.put("married", marriedExpectedDump);
|
||||||
|
|
||||||
Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
|
|
||||||
supervisorExpectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
|
||||||
|
|
||||||
supervisorExpectedDump.put(Key.VALUE.toString(), getJaneSmithExpectedDump(exposureLevel));
|
|
||||||
propertiesExpectedDump.put("supervisor", supervisorExpectedDump);
|
propertiesExpectedDump.put("supervisor", supervisorExpectedDump);
|
||||||
|
|
||||||
Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
|
Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
|
||||||
|
@ -1213,8 +1218,10 @@ public class DumpDirectiveTest {
|
||||||
|
|
||||||
expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);
|
expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel, "Doe"));
|
SortedMap<String, Object> methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Doe");
|
||||||
|
methodDump.put("boss()", supervisorExpectedDump);
|
||||||
|
expectedDump.put(Key.METHODS.toString(), methodDump);
|
||||||
|
|
||||||
return expectedDump;
|
return expectedDump;
|
||||||
}
|
}
|
||||||
|
@ -1250,6 +1257,9 @@ public class DumpDirectiveTest {
|
||||||
private Map<String, Object> getJaneSmithExpectedDump(int exposureLevel) {
|
private Map<String, Object> getJaneSmithExpectedDump(int exposureLevel) {
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
|
||||||
|
supervisorExpectedDump.put(Key.VALUE.toString(), Value.NULL);
|
||||||
|
|
||||||
SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();
|
SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();
|
||||||
|
|
||||||
|
@ -1289,8 +1299,6 @@ public class DumpDirectiveTest {
|
||||||
marriedExpectedDump.put(Key.VALUE.toString(), true);
|
marriedExpectedDump.put(Key.VALUE.toString(), true);
|
||||||
propertiesExpectedDump.put("married", marriedExpectedDump);
|
propertiesExpectedDump.put("married", marriedExpectedDump);
|
||||||
|
|
||||||
Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
|
|
||||||
supervisorExpectedDump.put(Key.VALUE.toString(), Value.NULL);
|
|
||||||
propertiesExpectedDump.put("supervisor", supervisorExpectedDump);
|
propertiesExpectedDump.put("supervisor", supervisorExpectedDump);
|
||||||
|
|
||||||
Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
|
Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
|
||||||
|
@ -1310,7 +1318,9 @@ public class DumpDirectiveTest {
|
||||||
expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);
|
expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel, "Smith"));
|
SortedMap<String, Object> methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Smith");
|
||||||
|
methodDump.put("boss()", supervisorExpectedDump);
|
||||||
|
expectedDump.put(Key.METHODS.toString(), methodDump);
|
||||||
|
|
||||||
return expectedDump;
|
return expectedDump;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue