NIHVIVO-1564 Continue work on object dump
This commit is contained in:
parent
8e3c13bd4c
commit
eb2995ac12
2 changed files with 134 additions and 103 deletions
|
@ -243,7 +243,9 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
|
|
||||||
private Map<String, Object> getTemplateModelData(TemplateHashModelEx model) throws TemplateModelException {
|
private Map<String, Object> getTemplateModelData(TemplateHashModelEx model) throws TemplateModelException {
|
||||||
Object unwrappedModel = DeepUnwrap.permissiveUnwrap(model);
|
Object unwrappedModel = DeepUnwrap.permissiveUnwrap(model);
|
||||||
// A key-value mapping.
|
// This seems to be the most reliable way of distinguishing a wrapped map from a wrapped object.
|
||||||
|
// A map may be wrapped as a SimpleHash, and an object may be wrapped as a StringModel, but they could
|
||||||
|
// be wrapped as other types as well.
|
||||||
if ( unwrappedModel instanceof Map ) {
|
if ( unwrappedModel instanceof Map ) {
|
||||||
return getMapData(model);
|
return getMapData(model);
|
||||||
}
|
}
|
||||||
|
@ -255,7 +257,6 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put(Key.TYPE.toString(), Type.HASH_EX);
|
map.put(Key.TYPE.toString(), Type.HASH_EX);
|
||||||
SortedMap<String, Object> items = new TreeMap<String, Object>();
|
SortedMap<String, Object> items = new TreeMap<String, Object>();
|
||||||
// keys() gets only values visible to template
|
|
||||||
TemplateCollectionModel keys = model.keys();
|
TemplateCollectionModel keys = model.keys();
|
||||||
TemplateModelIterator iModel = keys.iterator();
|
TemplateModelIterator iModel = keys.iterator();
|
||||||
while (iModel.hasNext()) {
|
while (iModel.hasNext()) {
|
||||||
|
@ -263,42 +264,71 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
TemplateModel value = model.get(key);
|
TemplateModel value = model.get(key);
|
||||||
items.put(key, getData(value));
|
items.put(key, getData(value));
|
||||||
}
|
}
|
||||||
// *** RY SORT keys alphabetically
|
|
||||||
map.put(Key.VALUE.toString(), items);
|
map.put(Key.VALUE.toString(), items);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getObjectData(TemplateHashModelEx model, Object object) throws TemplateModelException {
|
private Map<String, Object> getObjectData(TemplateHashModelEx model, Object object) throws TemplateModelException {
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
map.put(Key.TYPE.toString(), object.getClass().getName());
|
map.put(Key.TYPE.toString(), object.getClass().getName());
|
||||||
Set<Method> availableMethods = getMethodsAvailableToTemplate(model, object);
|
|
||||||
Map<String, Object> methods = new HashMap<String, Object>(availableMethods.size());
|
// Compile the set of properties and methods available to model
|
||||||
for ( Method method : availableMethods ) {
|
SortedMap<String, Object> availableMethods = new TreeMap<String, Object>();
|
||||||
String methodDisplayName = getMethodDisplayName(method);
|
|
||||||
if ( ! methodDisplayName.endsWith(")") ) {
|
// keys() gets only values visible to template based on the BeansWrapper used.
|
||||||
try {
|
// Note: if the BeansWrapper exposure level > BeansWrapper.EXPOSE_PROPERTIES_ONLY,
|
||||||
// See note in getAvailableMethods: when we have the keys, we can get the values without
|
// keys() returns both method and property name for any available method with no
|
||||||
// now invoking the method. Then getMethodsAvailableToTemplate should pass back
|
// parameters: e.g., both name and getName(). We are going to eliminate the latter.
|
||||||
// a map of keys to values.
|
TemplateCollectionModel keys = model.keys();
|
||||||
Object result = method.invoke(object);
|
TemplateModelIterator iModel = keys.iterator();
|
||||||
log.debug("Result of invoking method " + method.getName() + " is an object of type " + result.getClass().getName());
|
|
||||||
if (result instanceof TemplateModel) {
|
// Create a Set from keys so we can use the Set API.
|
||||||
log.debug("Sending result of invoking method " + method.getName() + " back through getData().");
|
Set<String> keySet = new HashSet<String>();
|
||||||
methods.put(methodDisplayName, getData((TemplateModel)result));
|
while (iModel.hasNext()) {
|
||||||
} else {
|
String key = iModel.next().toString();
|
||||||
log.debug("No further analysis on result of invoking method " + method.getName() + " is possible");
|
keySet.add(key);
|
||||||
methods.put(methodDisplayName, result.toString());
|
}
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
if (keySet.size() > 0) {
|
||||||
log.error("Error invoking method " + method.getName() + ". Cannot dump value.");
|
|
||||||
|
Class<?> cls = object.getClass();
|
||||||
|
Method[] methods = cls.getMethods();
|
||||||
|
|
||||||
|
// Iterate through the methods rather than the keys, so that we can remove
|
||||||
|
// some keys based on reflection on the methods. We also want to remove duplicates
|
||||||
|
// like name/getName - we'll keep only the first form.
|
||||||
|
for ( Method method : methods ) {
|
||||||
|
|
||||||
|
// Eliminate methods declared on Object
|
||||||
|
Class<?> c = method.getDeclaringClass();
|
||||||
|
if (c.equals(java.lang.Object.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminate deprecated methods
|
||||||
|
if (method.isAnnotationPresent(Deprecated.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include only methods included in keys(). This factors in visibility
|
||||||
|
// defined by the model's BeansWrapper.
|
||||||
|
String methodName = method.getName();
|
||||||
|
String propertyName = getPropertyName(methodName);
|
||||||
|
|
||||||
|
// If the method is available as a property, use that
|
||||||
|
if (keySet.contains(propertyName)) {
|
||||||
|
TemplateModel value = model.get(propertyName);
|
||||||
|
availableMethods.put(propertyName, getData(value));
|
||||||
|
// Else look for the entire methodName in the key set
|
||||||
|
} else if (keySet.contains(methodName)) {
|
||||||
|
String methodDisplayName = getMethodDisplayName(method);
|
||||||
|
availableMethods.put(methodDisplayName, "");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
methods.put(methodDisplayName, ""); // or null ?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** SORT methods alphabetically
|
map.put(Key.VALUE.toString(), availableMethods);
|
||||||
map.put(Key.VALUE.toString(), methods);
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,56 +353,10 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel {
|
||||||
return methodName;
|
return methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Method> getMethodsAvailableToTemplate(TemplateHashModelEx model, Object object) throws TemplateModelException {
|
// Return the method name as it is represented in TemplateHashModelEx.keys()
|
||||||
|
private String getPropertyName(String methodName) {
|
||||||
// keys() gets only values visible to template based on the BeansWrapper used.
|
String keyName = methodName.replaceAll("^(get|is)", "");
|
||||||
// Note: if the BeansWrapper exposure level > BeansWrapper.EXPOSE_PROPERTIES_ONLY,
|
return StringUtils.uncapitalize(keyName);
|
||||||
// keys() returns both method and property name for any available method with no
|
|
||||||
// parameters: e.g., both name and getName(). We are going to eliminate the latter.
|
|
||||||
TemplateCollectionModel keys = model.keys();
|
|
||||||
TemplateModelIterator iModel = keys.iterator();
|
|
||||||
Set<String> keySet = new HashSet<String>();
|
|
||||||
while (iModel.hasNext()) {
|
|
||||||
keySet.add(iModel.next().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> cls = object.getClass();
|
|
||||||
Method[] methods = cls.getMethods();
|
|
||||||
Set<Method> availableMethods = new HashSet<Method>();
|
|
||||||
for ( Method method : methods ) {
|
|
||||||
|
|
||||||
// Exclude static methods.
|
|
||||||
// int mod = method.getModifiers();
|
|
||||||
// if (Modifier.isStatic(mod)) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Eliminate methods declared on Object
|
|
||||||
Class<?> c = method.getDeclaringClass();
|
|
||||||
if (c.equals(java.lang.Object.class)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eliminate deprecated methods
|
|
||||||
if (method.isAnnotationPresent(Deprecated.class)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include only methods included in keys(). This factors in visibility
|
|
||||||
// defined by the model's BeansWrapper.
|
|
||||||
|
|
||||||
//*** This has to be method.getMethodDisplayName() ****
|
|
||||||
// SO: we have to get the display name now
|
|
||||||
// and we should get the value now too
|
|
||||||
// so method => { displayName => ..., value => ... }
|
|
||||||
if (keySet.contains(method.getName())) {
|
|
||||||
// if the key has a value, we could add it here rather than invoking the
|
|
||||||
// method later
|
|
||||||
availableMethods.add(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return availableMethods;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> getTemplateModelData(TemplateCollectionModel model) throws TemplateModelException {
|
private Map<String, Object> getTemplateModelData(TemplateCollectionModel model) throws TemplateModelException {
|
||||||
|
|
|
@ -625,13 +625,13 @@ public class DumpDirectiveTest {
|
||||||
try {
|
try {
|
||||||
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
||||||
} catch (TemplateModelException e) {
|
} catch (TemplateModelException e) {
|
||||||
// ??
|
// logging is suppressed, so what do we do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
expectedDump.put(Key.NAME.toString(), varName);
|
expectedDump.put(Key.NAME.toString(), varName);
|
||||||
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
||||||
expectedDump.put(Key.VALUE.toString(), new HashMap<String, Object>());
|
expectedDump.put(Key.VALUE.toString(), new TreeMap<String, Object>());
|
||||||
test(varName, dataModel, expectedDump);
|
test(varName, dataModel, expectedDump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,26 +645,34 @@ public class DumpDirectiveTest {
|
||||||
try {
|
try {
|
||||||
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
||||||
} catch (TemplateModelException e) {
|
} catch (TemplateModelException e) {
|
||||||
// ??
|
// logging is suppressed, so what do we do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
expectedDump.put(Key.NAME.toString(), varName);
|
expectedDump.put(Key.NAME.toString(), varName);
|
||||||
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
||||||
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
SortedMap<String, Object> properties = new TreeMap<String, Object>();
|
||||||
properties.put("fullName", "John Doe");
|
|
||||||
properties.put("nickname", "");
|
|
||||||
properties.put("id", 34523);
|
|
||||||
properties.put("supervisor", "");
|
|
||||||
properties.put("supervisees", "");
|
|
||||||
Calendar c = Calendar.getInstance();
|
Calendar c = Calendar.getInstance();
|
||||||
c.set(75, Calendar.MAY, 5);
|
c.set(75, Calendar.MAY, 5);
|
||||||
properties.put("birthdate", c.getTime());
|
properties.put("birthdate", c.getTime());
|
||||||
|
properties.put("fullName", "John Doe");
|
||||||
|
properties.put("id", 34523);
|
||||||
|
properties.put("nickname", "");
|
||||||
|
properties.put("supervisees", "");
|
||||||
|
properties.put("supervisor", "");
|
||||||
|
|
||||||
expectedDump.put(Key.VALUE.toString(), properties);
|
expectedDump.put(Key.VALUE.toString(), properties);
|
||||||
|
|
||||||
//test(varName, dataModel, expectedDump);
|
//Map<String, Object> dump = getDump(varName, dataModel);
|
||||||
|
//assertEquals(expectedDump, dump);
|
||||||
|
|
||||||
|
// Test the sorting of the methods
|
||||||
|
// List<String> expectedKeys = new ArrayList<String>(properties.keySet());
|
||||||
|
// @SuppressWarnings("unchecked")
|
||||||
|
// Map<String, Object> methodsActualDump = (Map<String, Object>) dump.get(Key.VALUE.toString());
|
||||||
|
// List<String> actualKeys = new ArrayList<String>(methodsActualDump.keySet());
|
||||||
|
//assertEquals(expectedKeys, actualKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -673,19 +681,38 @@ public class DumpDirectiveTest {
|
||||||
String varName = "employee";
|
String varName = "employee";
|
||||||
Map<String, Object> dataModel = new HashMap<String, Object>();
|
Map<String, Object> dataModel = new HashMap<String, Object>();
|
||||||
BeansWrapper wrapper = new BeansWrapper();
|
BeansWrapper wrapper = new BeansWrapper();
|
||||||
wrapper.setExposureLevel(BeansWrapper.EXPOSE_NOTHING);
|
wrapper.setExposureLevel(BeansWrapper.EXPOSE_SAFE);
|
||||||
try {
|
try {
|
||||||
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
||||||
} catch (TemplateModelException e) {
|
} catch (TemplateModelException e) {
|
||||||
// ??
|
// logging is suppressed, so what do we do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
expectedDump.put(Key.NAME.toString(), varName);
|
expectedDump.put(Key.NAME.toString(), varName);
|
||||||
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
||||||
expectedDump.put(Key.VALUE.toString(), new HashMap<String, Object>());
|
|
||||||
|
|
||||||
test(varName, dataModel, expectedDump);
|
SortedMap<String, Object> properties = new TreeMap<String, Object>();
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.set(75, Calendar.MAY, 5);
|
||||||
|
properties.put("birthdate", c.getTime());
|
||||||
|
properties.put("fullName", "John Doe");
|
||||||
|
properties.put("id", 34523);
|
||||||
|
properties.put("nickname", "");
|
||||||
|
properties.put("supervisees", "");
|
||||||
|
properties.put("supervisor", "");
|
||||||
|
|
||||||
|
expectedDump.put(Key.VALUE.toString(), properties);
|
||||||
|
|
||||||
|
//Map<String, Object> dump = getDump(varName, dataModel);
|
||||||
|
//assertEquals(expectedDump, dump);
|
||||||
|
|
||||||
|
// Test the sorting of the methods
|
||||||
|
// List<String> expectedKeys = new ArrayList<String>(properties.keySet());
|
||||||
|
// @SuppressWarnings("unchecked")
|
||||||
|
// Map<String, Object> methodsActualDump = (Map<String, Object>) dump.get(Key.VALUE.toString());
|
||||||
|
// List<String> actualKeys = new ArrayList<String>(methodsActualDump.keySet());
|
||||||
|
//assertEquals(expectedKeys, actualKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -694,18 +721,38 @@ public class DumpDirectiveTest {
|
||||||
String varName = "employee";
|
String varName = "employee";
|
||||||
Map<String, Object> dataModel = new HashMap<String, Object>();
|
Map<String, Object> dataModel = new HashMap<String, Object>();
|
||||||
BeansWrapper wrapper = new BeansWrapper();
|
BeansWrapper wrapper = new BeansWrapper();
|
||||||
wrapper.setExposureLevel(BeansWrapper.EXPOSE_NOTHING);
|
wrapper.setExposureLevel(BeansWrapper.EXPOSE_ALL);
|
||||||
try {
|
try {
|
||||||
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
dataModel.put("employee", wrapper.wrap(getEmployee()));
|
||||||
} catch (TemplateModelException e) {
|
} catch (TemplateModelException e) {
|
||||||
// ??
|
// logging is suppressed, so what do we do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
Map<String, Object> expectedDump = new HashMap<String, Object>();
|
||||||
expectedDump.put(Key.NAME.toString(), varName);
|
expectedDump.put(Key.NAME.toString(), varName);
|
||||||
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
expectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
|
||||||
expectedDump.put(Key.VALUE.toString(), new HashMap<String, Object>());
|
|
||||||
test(varName, dataModel, expectedDump);
|
SortedMap<String, Object> properties = new TreeMap<String, Object>();
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.set(75, Calendar.MAY, 5);
|
||||||
|
properties.put("birthdate", c.getTime());
|
||||||
|
properties.put("fullName", "John Doe");
|
||||||
|
properties.put("id", 34523);
|
||||||
|
properties.put("nickname", "");
|
||||||
|
properties.put("supervisees", "");
|
||||||
|
properties.put("supervisor", "");
|
||||||
|
|
||||||
|
expectedDump.put(Key.VALUE.toString(), properties);
|
||||||
|
|
||||||
|
//Map<String, Object> dump = getDump(varName, dataModel);
|
||||||
|
//assertEquals(expectedDump, dump);
|
||||||
|
|
||||||
|
// Test the sorting of the methods
|
||||||
|
// List<String> expectedKeys = new ArrayList<String>(properties.keySet());
|
||||||
|
// @SuppressWarnings("unchecked")
|
||||||
|
// Map<String, Object> methodsActualDump = (Map<String, Object>) dump.get(Key.VALUE.toString());
|
||||||
|
// List<String> actualKeys = new ArrayList<String>(methodsActualDump.keySet());
|
||||||
|
//assertEquals(expectedKeys, actualKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -929,8 +976,8 @@ public class DumpDirectiveTest {
|
||||||
List<Employee> supervisees = new ArrayList<Employee>();
|
List<Employee> supervisees = new ArrayList<Employee>();
|
||||||
supervisees.add(mjones);
|
supervisees.add(mjones);
|
||||||
supervisees.add(mturner);
|
supervisees.add(mturner);
|
||||||
jdoe.setSupervisor(jsmith);
|
//jdoe.setSupervisor(jsmith);
|
||||||
jdoe.setSupervisees(supervisees);
|
//jdoe.setSupervisees(supervisees);
|
||||||
jdoe.setSalary(65000);
|
jdoe.setSalary(65000);
|
||||||
|
|
||||||
return jdoe;
|
return jdoe;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue