From 6902a8373c02ddd7d555ee19bcdda9918dfa3b88 Mon Sep 17 00:00:00 2001 From: cramakri <cramakri> Date: Tue, 9 Nov 2010 12:11:09 +0000 Subject: [PATCH] LMS-1767 Refactored the escaper. SVN: 18602 --- .../utilities/ReflectingStringEscaper.java | 136 +++++++++++++++--- .../ReflectingStringEscaperTest.java | 52 ++++++- 2 files changed, 164 insertions(+), 24 deletions(-) diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java b/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java index 30c2635cf53..fee68b0dde0 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java @@ -23,31 +23,98 @@ import java.util.HashSet; import org.apache.commons.lang.StringEscapeUtils; /** - * Performs HTML escaping the string fields of an object. Restricts itself to the properties - * specified by the invoker. + * Performs HTML escaping the string fields of an object. If desired, users can restrict the fields + * that are escaped by the invoker. Support for controlling the behavior of the escaper by using + * annotations may come in the future. * * @author Chandrasekhar Ramakrishnan */ -public class ReflectingStringEscaper<T> +public class ReflectingStringEscaper { - public static <T> T escapeShallow(T bean, String... escapedProperties) + + /** + * Escape all the string fields on the bean. + */ + public static <T> T escapeShallow(T bean) + { + ReflectingStringEscaperUnrestricted<T> escaper = + new ReflectingStringEscaperUnrestricted<T>(false, bean); + return escaper.escape(); + } + + /** + * Escape all the string fields on the bean and all fields of objects referred to by the bean. + */ + public static <T> T escapeDeep(T bean) + { + ReflectingStringEscaperUnrestricted<T> escaper = + new ReflectingStringEscaperUnrestricted<T>(true, bean); + return escaper.escape(); + } + + /** + * Escape the specified string fields on the bean. + */ + public static <T> T escapeShallowRestricted(T bean, String... escapedProperties) { - ReflectingStringEscaper<T> escaper = - new ReflectingStringEscaper<T>(false, bean, escapedProperties); + ReflectingStringEscaperRestricted<T> escaper = + new ReflectingStringEscaperRestricted<T>(false, bean, escapedProperties); return escaper.escape(); } - public static <T> T escapeDeep(T bean, String... escapedProperties) + /** + * Escape all the string fields on the bean and all fields of objects referred to by the bean, + * restricting the field names to those specified. + */ + public static <T> T escapeDeepRestricted(T bean, String... escapedProperties) { - ReflectingStringEscaper<T> escaper = - new ReflectingStringEscaper<T>(true, bean, escapedProperties); + ReflectingStringEscaperRestricted<T> escaper = + new ReflectingStringEscaperRestricted<T>(true, bean, escapedProperties); return escaper.escape(); } +} + +/** + * @author Chandrasekhar Ramakrishnan + */ +class ReflectingStringEscaperImpl<T> +{ + + protected final boolean isDeep; + + protected final T bean; + + /** + * + * + */ + protected ReflectingStringEscaperImpl(boolean isDeep, T bean) + { + this.isDeep = isDeep; + this.bean = bean; + } - private final boolean isDeep; + protected T escape(ReflectionStringTraverser.ReflectionFieldVisitor visitor) + { + if (isDeep) + { + ReflectionStringTraverser.traverseDeep(bean, visitor); + } else + { + ReflectionStringTraverser.traverseShallow(bean, visitor); + } + return bean; + } - private final T bean; +} +/** + * Utility Class that preforms the restricted escaping. + * + * @author Chandrasekhar Ramakrishnan + */ +class ReflectingStringEscaperRestricted<T> extends ReflectingStringEscaperImpl<T> +{ private final HashSet<String> escapedProperties; private class Visitor implements ReflectionStringTraverser.ReflectionFieldVisitor @@ -66,23 +133,50 @@ public class ReflectingStringEscaper<T> } } - private ReflectingStringEscaper(boolean isDeep, T bean, String... escapedProperties) + ReflectingStringEscaperRestricted(boolean isDeep, T bean, String... escapedProperties) { - this.isDeep = isDeep; - this.bean = bean; + super(isDeep, bean); this.escapedProperties = new HashSet<String>(); Collections.addAll(this.escapedProperties, escapedProperties); } - private T escape() + T escape() { - if (isDeep) - { - ReflectionStringTraverser.traverseDeep(bean, new Visitor()); - } else + return escape(new Visitor()); + } +} + +/** + * Utility Class that preforms the unrestricted escaping. + * + * @author Chandrasekhar Ramakrishnan + */ +class ReflectingStringEscaperUnrestricted<T> extends ReflectingStringEscaperImpl<T> +{ + + private static class Visitor implements ReflectionStringTraverser.ReflectionFieldVisitor + { + + public String tryVisit(String value, Object object, Field fieldOrNull) { - ReflectionStringTraverser.traverseShallow(bean, new Visitor()); + // Only change the value if the name of the field is in the list provided + if (null == fieldOrNull) + { + return null; + } + + return StringEscapeUtils.escapeHtml(value); + } - return bean; + } + + ReflectingStringEscaperUnrestricted(boolean isDeep, T bean) + { + super(isDeep, bean); + } + + T escape() + { + return escape(new Visitor()); } } diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java index 03a6b0c4273..d50f77a981f 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java @@ -47,10 +47,10 @@ public class ReflectingStringEscaperTest extends AssertJUnit bean.wrappedBean.bar = "<b>bar</b>"; bean.wrappedBean.baz = "<i>baz</i>"; - TestBean escaped = ReflectingStringEscaper.escapeShallow(bean, "foo", "baz"); + TestBean escaped = ReflectingStringEscaper.escapeShallow(bean); assertEquals(bean, escaped); assertEquals("<a>foo</a>", bean.foo); - assertEquals("<b>bar</b>", bean.bar); + assertEquals("<b>bar</b>", bean.bar); assertEquals("<i>baz</i>", bean.baz); assertEquals("<a>foo</a>", bean.wrappedBean.foo); @@ -70,7 +70,53 @@ public class ReflectingStringEscaperTest extends AssertJUnit bean.wrappedBean.bar = "<b>bar</b>"; bean.wrappedBean.baz = "<i>baz</i>"; - TestBean escaped = ReflectingStringEscaper.escapeDeep(bean, "foo", "baz"); + TestBean escaped = ReflectingStringEscaper.escapeDeep(bean); + assertEquals(bean, escaped); + assertEquals("<a>foo</a>", bean.foo); + assertEquals("<b>bar</b>", bean.bar); + assertEquals("<i>baz</i>", bean.baz); + + assertEquals("<a>foo</a>", bean.wrappedBean.foo); + assertEquals("<b>bar</b>", bean.wrappedBean.bar); + assertEquals("<i>baz</i>", bean.wrappedBean.baz); + } + + @Test + public void testShallowEscaperRestricted() + { + TestBean bean = new TestBean(); + bean.foo = "<a>foo</a>"; + bean.bar = "<b>bar</b>"; + bean.baz = "<i>baz</i>"; + bean.wrappedBean = new TestBean(); + bean.wrappedBean.foo = "<a>foo</a>"; + bean.wrappedBean.bar = "<b>bar</b>"; + bean.wrappedBean.baz = "<i>baz</i>"; + + TestBean escaped = ReflectingStringEscaper.escapeShallowRestricted(bean, "foo", "baz"); + assertEquals(bean, escaped); + assertEquals("<a>foo</a>", bean.foo); + assertEquals("<b>bar</b>", bean.bar); + assertEquals("<i>baz</i>", bean.baz); + + assertEquals("<a>foo</a>", bean.wrappedBean.foo); + assertEquals("<b>bar</b>", bean.wrappedBean.bar); + assertEquals("<i>baz</i>", bean.wrappedBean.baz); + } + + @Test + public void testDeepEscaperRestricted() + { + TestBean bean = new TestBean(); + bean.foo = "<a>foo</a>"; + bean.bar = "<b>bar</b>"; + bean.baz = "<i>baz</i>"; + bean.wrappedBean = new TestBean(); + bean.wrappedBean.foo = "<a>foo</a>"; + bean.wrappedBean.bar = "<b>bar</b>"; + bean.wrappedBean.baz = "<i>baz</i>"; + + TestBean escaped = ReflectingStringEscaper.escapeDeepRestricted(bean, "foo", "baz"); assertEquals(bean, escaped); assertEquals("<a>foo</a>", bean.foo); assertEquals("<b>bar</b>", bean.bar); -- GitLab