diff --git a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java index 265eb09d4..c26084fc5 100644 --- a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java +++ b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java @@ -7,6 +7,7 @@ import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -14,6 +15,8 @@ import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -47,10 +50,12 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { private static final Log log = LogFactory.getLog(BaseDumpDirective.class); + Pattern PROPERTY_NAME_PATTERN = Pattern.compile("^(get|is)\\w"); + enum Key { METHODS("methods"), NAME("name"), - PROPERTIES(Key.METHODS.toString()), + PROPERTIES("properties"), TYPE("type"), VALUE("value"), DATE_TYPE("dateType"); @@ -289,7 +294,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { // Compile the sets of properties and methods available to template SortedMap properties = new TreeMap(); - SortedMap methods = new TreeMap(); + List methods = new ArrayList(); // keys() gets only values visible to template based on the BeansWrapper used. // Note: if the BeansWrapper exposure level > BeansWrapper.EXPOSE_PROPERTIES_ONLY, @@ -329,23 +334,35 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { // 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); - properties.put(propertyName, getData(value)); - // Else look for the entire methodName in the key set - } else if (keySet.contains(methodName)) { + + Matcher matcher = PROPERTY_NAME_PATTERN.matcher(methodName); + // If the method name starts with "get" or "is", check if it's available + // as a property + if (matcher.find()) { + String propertyName = getPropertyName(methodName); + + // The method is available as a property + if (keySet.contains(propertyName)) { + TemplateModel value = model.get(propertyName); + properties.put(propertyName, getData(value)); + continue; + } + } + // Else look for the entire methodName in the key set. Include those + // starting with "get" or "is" that were not found above. + if (keySet.contains(methodName)) { String methodDisplayName = getMethodDisplayName(method); - methods.put(methodDisplayName, ""); + methods.add(methodDisplayName); } } } Map objectValue = new HashMap(2); objectValue.put(Key.PROPERTIES.toString(), properties); + + Collections.sort(methods); objectValue.put(Key.METHODS.toString(), methods); + map.put(Key.VALUE.toString(), objectValue); return map; } @@ -363,9 +380,6 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { paramTypeList.add(typeName); } methodName += "(" + StringUtils.join(paramTypeList, ", ") + ")"; - } else { - methodName = methodName.replaceAll("^(get|is)", ""); - methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1); } return methodName; diff --git a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java index 71f079fec..3a4dbc209 100644 --- a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java +++ b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java @@ -12,6 +12,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -645,12 +646,12 @@ public class DumpDirectiveTest { @Test public void dumpObjectWithExposeSafeWrapper() { - //dumpObject(BeansWrapper.EXPOSE_SAFE); + dumpObject(BeansWrapper.EXPOSE_SAFE); } @Test public void dumpObjectWithExposeAllWrapper() { - //dumpObject(BeansWrapper.EXPOSE_ALL); + dumpObject(BeansWrapper.EXPOSE_ALL); } @@ -686,7 +687,7 @@ public class DumpDirectiveTest { Map dump = getDump(varName, dataModel); assertEquals(expectedDump, dump); - // Test the sorting of the properties and methods + // Test the sorting of the properties @SuppressWarnings("unchecked") Map valueExpectedDump = (Map) expectedDump.get(Key.VALUE.toString()); @SuppressWarnings("unchecked") @@ -700,15 +701,7 @@ public class DumpDirectiveTest { Map propertiesActualDump = (Map) valueActualDump.get(Key.PROPERTIES.toString()); List propertyKeysActual = new ArrayList(propertiesActualDump.keySet()); assertEquals(propertyKeysExpected, propertyKeysActual); - - @SuppressWarnings("unchecked") - Map methodsExpectedDump = (Map) valueExpectedDump.get(Key.METHODS.toString()); - List methodKeysExpected = new ArrayList(methodsExpectedDump.keySet()); - @SuppressWarnings("unchecked") - Map methodsActualDump = (Map) valueActualDump.get(Key.METHODS.toString()); - List methodKeysActual = new ArrayList(methodsActualDump.keySet()); - assertEquals(methodKeysExpected, methodKeysActual); - + } private Map getDump(String varName, Map dataModel) { @@ -721,8 +714,6 @@ public class DumpDirectiveTest { } } - - private class HelplessMethod implements TemplateMethodModel { @Override @@ -853,7 +844,7 @@ public class DumpDirectiveTest { count++; } - void setSupervisor(Employee supervisor) { + protected void setSupervisor(Employee supervisor) { this.supervisor = supervisor; } @@ -1002,11 +993,22 @@ public class DumpDirectiveTest { expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump); - // Methods + // Methods + expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel)); - SortedMap methodsExpectedDump = new TreeMap(); - expectedDump.put(Key.METHODS.toString(), methodsExpectedDump); + return expectedDump; + } + + private List getEmployeeMethodsExpectedDump(int exposureLevel) { + List expectedDump = new ArrayList(); + if (exposureLevel == BeansWrapper.EXPOSE_SAFE || exposureLevel == BeansWrapper.EXPOSE_ALL) { + expectedDump.add("getEmployeeCount"); + expectedDump.add("getName(String)"); + expectedDump.add("setFavoriteColors(Strings)"); + expectedDump.add("setNickname(String)"); + } + Collections.sort(expectedDump); return expectedDump; } @@ -1072,8 +1074,7 @@ public class DumpDirectiveTest { expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump); // Methods - SortedMap methodsExpectedDump = new TreeMap(); - expectedDump.put(Key.METHODS.toString(), methodsExpectedDump); + expectedDump.put(Key.METHODS.toString(), getEmployeeMethodsExpectedDump(exposureLevel)); return expectedDump; }