NIHVIVO-1564 In dump of template model objects, hide methods that take arguments unless the BeansWrapper exposure level exposes these methods to the template.
This commit is contained in:
parent
97e6630eb7
commit
af7d959ecd
5 changed files with 69 additions and 37 deletions
|
@ -71,7 +71,7 @@ public class DescribeDirective extends BaseTemplateDirectiveModel {
|
|||
}
|
||||
|
||||
DumpHelper helper = new DumpHelper(env);
|
||||
List<Method> methods = helper.getMethodsAvailableToTemplate(unwrappedModel.getClass());
|
||||
List<Method> methods = helper.getMethodsAvailableToTemplate(tm, unwrappedModel.getClass());
|
||||
List<String> methodDisplayNames = new ArrayList<String>(methods.size());
|
||||
for (Method m : methods) {
|
||||
methodDisplayNames.add(helper.getMethodDisplayName(m));
|
||||
|
|
|
@ -18,11 +18,12 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
|
|||
import edu.cornell.mannlib.vitro.webapp.web.directives.BaseTemplateDirectiveModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.ext.beans.BeanModel;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.ext.beans.WrapperExtractor;
|
||||
import freemarker.template.TemplateBooleanModel;
|
||||
import freemarker.template.TemplateDateModel;
|
||||
import freemarker.template.TemplateDirectiveModel;
|
||||
import freemarker.template.TemplateHashModel;
|
||||
import freemarker.template.TemplateMethodModel;
|
||||
import freemarker.template.TemplateModel;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import freemarker.template.TemplateNumberModel;
|
||||
|
@ -44,7 +45,7 @@ public class DumpHelper {
|
|||
return BaseTemplateDirectiveModel.processTemplateToString("dump-var.ftl", map, env);
|
||||
}
|
||||
|
||||
public Map<String, Object> getVariableDumpData(String varName) {
|
||||
private Map<String, Object> getVariableDumpData(String varName) {
|
||||
TemplateHashModel dataModel = env.getDataModel();
|
||||
|
||||
TemplateModel tm = null;
|
||||
|
@ -86,7 +87,7 @@ public class DumpHelper {
|
|||
// view in the dump. Not sure if we should handle our application-specific, non-template
|
||||
// model objects in the same way. For now, these get assigned a shorthand type below.
|
||||
if (unwrappedModel instanceof BaseTemplateModel) {
|
||||
value = getTemplateModelDump((BaseTemplateModel)unwrappedModel); //((BaseTemplateModel)unwrappedModel).dump();
|
||||
value = getTemplateModelDump(tm, (BaseTemplateModel)unwrappedModel); //((BaseTemplateModel)unwrappedModel).dump();
|
||||
type = className;
|
||||
}
|
||||
// Can't use this, because tm of (at least some) POJOs are
|
||||
|
@ -109,10 +110,6 @@ public class DumpHelper {
|
|||
type = "Sequence";
|
||||
} else if (tm instanceof TemplateHashModel) {
|
||||
type = "Hash";
|
||||
// In recursive dump, we've gotten down to a raw string. Just output it.
|
||||
// } else if (val == null) {
|
||||
// out.write(var);
|
||||
// return;
|
||||
} else {
|
||||
// One of the above cases should have applied. Just in case not, show the Java class name.
|
||||
type = className;
|
||||
|
@ -120,7 +117,6 @@ public class DumpHelper {
|
|||
|
||||
map.put("value", value);
|
||||
map.put("type", type);
|
||||
|
||||
}
|
||||
|
||||
return map;
|
||||
|
@ -136,28 +132,40 @@ public class DumpHelper {
|
|||
}
|
||||
}
|
||||
|
||||
protected List<Method> getMethodsAvailableToTemplate(Class<?> cls) {
|
||||
protected List<Method> getMethodsAvailableToTemplate(TemplateModel wrappedModel, Class<?> cls) {
|
||||
List<Method> methods = new ArrayList<Method>();
|
||||
|
||||
// Go up the class hierarchy only as far as the immediate subclass of BaseTemplateModel
|
||||
if (! cls.getName().equals("edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel")) {
|
||||
methods = getDeclaredPublicMethods(cls);
|
||||
methods.addAll(getMethodsAvailableToTemplate(cls.getSuperclass()));
|
||||
methods = getDeclaredMethodsAvailableToTemplate(wrappedModel, cls);
|
||||
methods.addAll(getMethodsAvailableToTemplate(wrappedModel, cls.getSuperclass()));
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
private List<Method> getDeclaredPublicMethods(Class<?> cls) {
|
||||
private List<Method> getDeclaredMethodsAvailableToTemplate(TemplateModel wrappedModel, Class<?> cls) {
|
||||
|
||||
List<Method> methods = new ArrayList<Method>();
|
||||
Method[] declaredMethods = cls.getDeclaredMethods();
|
||||
for (Method m : declaredMethods) {
|
||||
int mod = m.getModifiers();
|
||||
for (Method method : declaredMethods) {
|
||||
int mod = method.getModifiers();
|
||||
if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) {
|
||||
// If the method takes args, make sure the BeanWrapper used makes this method visible.
|
||||
// RY It may not be possible to determine this.
|
||||
methods.add(m);
|
||||
Class<?>[] params = method.getParameterTypes();
|
||||
// If the method takes arguments...
|
||||
if (params.length > 0) {
|
||||
// Unless the object has been wrapped with a non-default BeansWrapper with an exposure
|
||||
// level that is more permissive than the Configuration's default BeansWrapper, this
|
||||
// method is not visible to the template.
|
||||
if ( ! ( wrappedModel instanceof BeanModel ) ) {
|
||||
continue;
|
||||
}
|
||||
int exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel)wrappedModel);
|
||||
if ( exposureLevel > BeansWrapper.EXPOSE_SAFE ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
|
@ -186,11 +194,15 @@ public class DumpHelper {
|
|||
return methodName + paramList;
|
||||
}
|
||||
|
||||
private String getTemplateModelDump(BaseTemplateModel model) {
|
||||
private String getTemplateModelDump(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) {
|
||||
|
||||
// if (tm instanceof BeanModel) {
|
||||
// int exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) tm);
|
||||
// log.debug(varName + " is an instance of BeanModel. Exposure level = " + exposureLevel);
|
||||
// }
|
||||
|
||||
log.debug(model.getClass());
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
List<Method> publicMethods = getMethodsAvailableToTemplate(model.getClass());
|
||||
List<Method> publicMethods = getMethodsAvailableToTemplate(wrappedModel, unwrappedModel.getClass());
|
||||
Map<String, String> properties = new HashMap<String, String>();
|
||||
List<String> methods = new ArrayList<String>();
|
||||
for (Method method : publicMethods) {
|
||||
|
@ -200,18 +212,8 @@ public class DumpHelper {
|
|||
methods.add(key);
|
||||
} else {
|
||||
try {
|
||||
Object result = method.invoke(model);
|
||||
String value = null;
|
||||
if (result == null) {
|
||||
value = "null"; // distinguish a null from an empty string
|
||||
// } else if (result instanceof TemplateDirectiveModel) {
|
||||
// // value = string output of the help() method processed through template
|
||||
// } else if (result instanceof TemplateMethodModel) {
|
||||
// // value = string output of the help() method processed through template
|
||||
} else {
|
||||
value = result.toString();
|
||||
}
|
||||
|
||||
Object result = method.invoke(unwrappedModel);
|
||||
String value = result == null ? "null" : result.toString();
|
||||
properties.put(key, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e, e);
|
||||
|
|
20
webapp/src/freemarker/ext/beans/WrapperExtractor.java
Normal file
20
webapp/src/freemarker/ext/beans/WrapperExtractor.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package freemarker.ext.beans;
|
||||
|
||||
import freemarker.template.TemplateModel;
|
||||
|
||||
/**
|
||||
* Class to extract information about the wrapper used to wrap an object in
|
||||
* the template model.
|
||||
*/
|
||||
public class WrapperExtractor {
|
||||
|
||||
public static BeansWrapper getWrapper(BeanModel model) {
|
||||
return model.wrapper;
|
||||
}
|
||||
|
||||
public static int getWrapperExposureLevel(BeanModel model) {
|
||||
return model.wrapper.getExposureLevel();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<#-- Template for dumping a template model object -->
|
||||
<#-- Template for dumping the value template model object -->
|
||||
|
||||
|
||||
<#if properties?has_content>
|
||||
<p><strong>Property values</strong></p>
|
||||
<ul>
|
||||
<#list properties?keys as property>
|
||||
<li>${property}: ${properties[property]?html}</li>
|
||||
|
@ -11,9 +13,13 @@
|
|||
</#if>
|
||||
|
||||
<#if methods?has_content>
|
||||
<p><strong>Methods</strong></p>
|
||||
<ul>
|
||||
<#list methods as method>
|
||||
<li>${method}</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</#if>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,3 +3,7 @@
|
|||
<#-- FreeMarker test cases -->
|
||||
|
||||
<h2>${title}</h2>
|
||||
|
||||
<@dumpAll />
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue