NIHVIVO-1564 Handle one level of nesting of template model objects in variable dump
This commit is contained in:
parent
b92a9c483d
commit
cdaaf369f0
3 changed files with 88 additions and 19 deletions
|
@ -13,6 +13,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringEscapeUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
@ -87,11 +88,10 @@ public class DumpHelper {
|
||||||
if (unwrappedModel instanceof BaseTemplateModel) {
|
if (unwrappedModel instanceof BaseTemplateModel) {
|
||||||
map.putAll(getTemplateModelValues(tm, (BaseTemplateModel)unwrappedModel));
|
map.putAll(getTemplateModelValues(tm, (BaseTemplateModel)unwrappedModel));
|
||||||
type = className;
|
type = className;
|
||||||
}
|
|
||||||
// Can't use this, because tm of (at least some) POJOs are
|
// Can't use this, because tm of (at least some) POJOs are
|
||||||
// StringModels, which are both TemplateScalarModels and TemplateHashModels
|
// StringModels, which are both TemplateScalarModels and TemplateHashModels
|
||||||
// if (tm instanceof TemplateScalarModel)
|
// if (tm instanceof TemplateScalarModel)
|
||||||
else if (unwrappedModel instanceof String) {
|
} else if (unwrappedModel instanceof String) {
|
||||||
type = "String";
|
type = "String";
|
||||||
} else if (tm instanceof TemplateDateModel) {
|
} else if (tm instanceof TemplateDateModel) {
|
||||||
type = "Date";
|
type = "Date";
|
||||||
|
@ -136,22 +136,27 @@ public class DumpHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Method> getMethodsAvailableToTemplate(TemplateModel wrappedModel, Class<?> cls) {
|
protected List<Method> getMethodsAvailableToTemplate(TemplateModel wrappedModel, Class<?> cls) {
|
||||||
|
int exposureLevel = getExposureLevel(wrappedModel, cls);
|
||||||
|
return getMethodsAvailableToTemplate(exposureLevel, cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getExposureLevel(TemplateModel model, Class<?> cls) {
|
||||||
|
|
||||||
int exposureLevel;
|
int exposureLevel;
|
||||||
// Get the exposure level of the BeansWrapper that wrapped this object.
|
// Get the exposure level of the BeansWrapper that wrapped this object.
|
||||||
if (wrappedModel instanceof BeanModel) {
|
if (model instanceof BeanModel) {
|
||||||
exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) wrappedModel);
|
exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) model);
|
||||||
log.debug("Exposure level for class " + cls.getCanonicalName() + " of type " + wrappedModel.getClass() + " = " + exposureLevel);
|
log.debug("Exposure level for class " + cls.getCanonicalName() + " of type " + model.getClass() + " = " + exposureLevel);
|
||||||
// We don't expect to get here, since we are dealing only with BaseTemplateModel objects, which get wrapped into BeanModel objects,
|
// We don't expect to get here, since we are dealing only with BaseTemplateModel objects, which get wrapped into BeanModel objects,
|
||||||
// but it's here as a safety net.
|
// but it's here as a safety net.
|
||||||
} else {
|
} else {
|
||||||
HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request");
|
HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request");
|
||||||
Configuration config = (Configuration) request.getAttribute("freemarkerConfig");
|
Configuration config = (Configuration) request.getAttribute("freemarkerConfig");
|
||||||
exposureLevel = (Integer) config.getCustomAttribute("defaultExposureLevel");
|
exposureLevel = (Integer) config.getCustomAttribute("defaultExposureLevel");
|
||||||
log.debug("Class " + cls.getCanonicalName() + " of type " + wrappedModel.getClass() + " uses default exposure level " + exposureLevel);
|
log.debug("Class " + cls.getCanonicalName() + " of type " + model.getClass() + " uses default exposure level " + exposureLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMethodsAvailableToTemplate(exposureLevel, cls);
|
return exposureLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Method> getMethodsAvailableToTemplate(int exposureLevel, Class<?> cls) {
|
private List<Method> getMethodsAvailableToTemplate(int exposureLevel, Class<?> cls) {
|
||||||
|
@ -187,11 +192,7 @@ public class DumpHelper {
|
||||||
|
|
||||||
protected String getMethodDisplayName(Method method) {
|
protected String getMethodDisplayName(Method method) {
|
||||||
String methodName = method.getName();
|
String methodName = method.getName();
|
||||||
methodName = methodName.replaceAll("^(get|is)", "");
|
|
||||||
methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
|
|
||||||
|
|
||||||
Class<?>[] paramTypes = method.getParameterTypes();
|
Class<?>[] paramTypes = method.getParameterTypes();
|
||||||
String paramList = "";
|
|
||||||
if (paramTypes.length > 0) {
|
if (paramTypes.length > 0) {
|
||||||
List<String> paramTypeList = new ArrayList<String>(paramTypes.length);
|
List<String> paramTypeList = new ArrayList<String>(paramTypes.length);
|
||||||
for (Class<?> cls : paramTypes) {
|
for (Class<?> cls : paramTypes) {
|
||||||
|
@ -202,10 +203,13 @@ public class DumpHelper {
|
||||||
typeName = typeName.substring(0,1).toLowerCase() + typeName.substring(1);
|
typeName = typeName.substring(0,1).toLowerCase() + typeName.substring(1);
|
||||||
paramTypeList.add(typeName);
|
paramTypeList.add(typeName);
|
||||||
}
|
}
|
||||||
paramList = "(" + StringUtils.join(paramTypeList) + ")";
|
methodName += "(" + StringUtils.join(paramTypeList) + ")";
|
||||||
|
} else {
|
||||||
|
methodName = methodName.replaceAll("^(get|is)", "");
|
||||||
|
methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return methodName + paramList;
|
return methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getTemplateModelValues(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) {
|
private Map<String, Object> getTemplateModelValues(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) {
|
||||||
|
@ -213,7 +217,8 @@ public class DumpHelper {
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put("value", unwrappedModel.dump());
|
map.put("value", unwrappedModel.dump());
|
||||||
|
|
||||||
List<Method> publicMethods = getMethodsAvailableToTemplate(wrappedModel, unwrappedModel.getClass());
|
int exposureLevel = getExposureLevel(wrappedModel, unwrappedModel.getClass());
|
||||||
|
List<Method> publicMethods = getMethodsAvailableToTemplate(exposureLevel, unwrappedModel.getClass());
|
||||||
Map<String, String> properties = new HashMap<String, String>();
|
Map<String, String> properties = new HashMap<String, String>();
|
||||||
List<String> methods = new ArrayList<String>();
|
List<String> methods = new ArrayList<String>();
|
||||||
for (Method method : publicMethods) {
|
for (Method method : publicMethods) {
|
||||||
|
@ -227,7 +232,16 @@ public class DumpHelper {
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Object result = method.invoke(unwrappedModel);
|
Object result = method.invoke(unwrappedModel);
|
||||||
String value = result == null ? "null" : result.toString();
|
String value;
|
||||||
|
if (result == null) {
|
||||||
|
value = "null";
|
||||||
|
} else if (result instanceof BaseTemplateModel) {
|
||||||
|
value = getTemplateModelDump((BaseTemplateModel)result, exposureLevel);
|
||||||
|
} else {
|
||||||
|
// Don't use ?html in the template, because then the output of
|
||||||
|
// getTemplateModelDump, which is html, gets escaped too.
|
||||||
|
value = StringEscapeUtils.escapeHtml(result.toString());
|
||||||
|
}
|
||||||
properties.put(key, value);
|
properties.put(key, value);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e, e);
|
log.error(e, e);
|
||||||
|
@ -241,4 +255,52 @@ public class DumpHelper {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getTemplateModelDump(BaseTemplateModel model, int exposureLevel) {
|
||||||
|
// What we need to do here is recurse down into the model and display the value, type,
|
||||||
|
// properties, and methods for each one. Pull out the part shared by this and getTemplateModelValues
|
||||||
|
// into a common method. This will return the string so that the template doesn't have to follow
|
||||||
|
// the recursion.
|
||||||
|
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("value", model.dump());
|
||||||
|
|
||||||
|
List<Method> publicMethods = getMethodsAvailableToTemplate(exposureLevel, model.getClass());
|
||||||
|
Map<String, String> properties = new HashMap<String, String>();
|
||||||
|
List<String> methods = new ArrayList<String>();
|
||||||
|
for (Method method : publicMethods) {
|
||||||
|
// Don't include the dump method, since this is used above to provide the value of the object.
|
||||||
|
if (method.getName().equals("dump")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String key = getMethodDisplayName(method);
|
||||||
|
if (key.endsWith(")")) {
|
||||||
|
methods.add(key);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Object result = method.invoke(model);
|
||||||
|
String value;
|
||||||
|
if (result == null) {
|
||||||
|
value = "null";
|
||||||
|
} else if (result instanceof BaseTemplateModel) {
|
||||||
|
value = getTemplateModelDump((BaseTemplateModel)result, exposureLevel);
|
||||||
|
} else {
|
||||||
|
// Don't use ?html in the template, because then the output of
|
||||||
|
// getTemplateModelDump, which is html, gets escaped too.
|
||||||
|
value = StringEscapeUtils.escapeHtml(result.toString());
|
||||||
|
}
|
||||||
|
properties.put(key, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put("type", model.getClass().getName());
|
||||||
|
map.put("properties", properties);
|
||||||
|
map.put("methods", methods);
|
||||||
|
|
||||||
|
return BaseTemplateDirectiveModel.processTemplateToString("dump-var.ftl", map, env);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,3 +41,7 @@
|
||||||
.dump .directive ol li {
|
.dump .directive ol li {
|
||||||
list-style: decimal inside none;
|
list-style: decimal inside none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.var .var {
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
<#-- Template for dumping a template variable -->
|
<#-- Template for dumping a template variable -->
|
||||||
|
|
||||||
<div class="var">
|
<div class="var">
|
||||||
<p><strong>Variable name: ${var}</strong></p>
|
<#if var??> <#-- not defined for a nested template model object -->
|
||||||
|
<p><strong>Variable name: ${var}</strong></p>
|
||||||
|
</#if>
|
||||||
|
|
||||||
<#if value??>
|
<#if value??>
|
||||||
<p><strong>Type:</strong> ${type}</p>
|
<p><strong>Type:</strong> ${type}</p>
|
||||||
<p><strong>Value:</strong> ${value}</p>
|
<p><strong>Value:</strong> ${value}</p>
|
||||||
|
@ -13,7 +16,7 @@
|
||||||
<p><strong>Properties:</strong></p>
|
<p><strong>Properties:</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<#list properties?keys as property>
|
<#list properties?keys as property>
|
||||||
<li>${property}: ${properties[property]?html}</li>
|
<li>${property}: ${properties[property]}</li>
|
||||||
</#list>
|
</#list>
|
||||||
</ul>
|
</ul>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
Loading…
Add table
Reference in a new issue