You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sk...@apache.org on 2004/02/16 03:26:38 UTC
cvs commit: jakarta-commons/digester/src/test/org/apache/commons/digester CallMethodRuleTestCase.java
skitching 2004/02/15 18:26:38
Modified: digester/src/java/org/apache/commons/digester
CallMethodRule.java
digester/src/test/org/apache/commons/digester
CallMethodRuleTestCase.java
Log:
Allow CallMethodRule to target any object on the digester object stack,
not just the top one. In particular, allow it to act like SetNextRule.
Revision Changes Path
1.29 +127 -14 jakarta-commons/digester/src/java/org/apache/commons/digester/CallMethodRule.java
Index: CallMethodRule.java
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/CallMethodRule.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- CallMethodRule.java 10 Jan 2004 17:32:28 -0000 1.28
+++ CallMethodRule.java 16 Feb 2004 02:26:38 -0000 1.29
@@ -98,7 +98,6 @@
public class CallMethodRule extends Rule {
-
// ----------------------------------------------------------- Constructors
@@ -179,7 +178,26 @@
*/
public CallMethodRule(String methodName,
int paramCount) {
+ this(0, methodName, paramCount);
+ }
+ /**
+ * Construct a "call method" rule with the specified method name. The
+ * parameter types (if any) default to java.lang.String.
+ *
+ * @param targetOffset location of the target object. Positive numbers are
+ * relative to the top of the digester object stack. Negative numbers
+ * are relative to the bottom of the stack. Zero implies the top
+ * object on the stack.
+ * @param methodName Method name of the parent method to call
+ * @param paramCount The number of parameters to collect, or
+ * zero for a single argument from the body of this element.
+ */
+ public CallMethodRule(int targetOffset,
+ String methodName,
+ int paramCount) {
+
+ this.targetOffset = targetOffset;
this.methodName = methodName;
this.paramCount = paramCount;
if (paramCount == 0) {
@@ -201,7 +219,24 @@
*/
public CallMethodRule(String methodName) {
- this(methodName, 0, (Class[]) null);
+ this(0, methodName, 0, (Class[]) null);
+
+ }
+
+
+ /**
+ * Construct a "call method" rule with the specified method name.
+ * The method should accept no parameters.
+ *
+ * @param targetOffset location of the target object. Positive numbers are
+ * relative to the top of the digester object stack. Negative numbers
+ * are relative to the bottom of the stack. Zero implies the top
+ * object on the stack.
+ * @param methodName Method name of the parent method to call
+ */
+ public CallMethodRule(int targetOffset, String methodName) {
+
+ this(targetOffset, methodName, 0, (Class[]) null);
}
@@ -225,7 +260,34 @@
String methodName,
int paramCount,
String paramTypes[]) {
+ this(0, methodName, paramCount, paramTypes);
+ }
+ /**
+ * Construct a "call method" rule with the specified method name and
+ * parameter types. If <code>paramCount</code> is set to zero the rule
+ * will use the body of this element as the single argument of the
+ * method, unless <code>paramTypes</code> is null or empty, in this
+ * case the rule will call the specified method with no arguments.
+ *
+ * @param targetOffset location of the target object. Positive numbers are
+ * relative to the top of the digester object stack. Negative numbers
+ * are relative to the bottom of the stack. Zero implies the top
+ * object on the stack.
+ * @param methodName Method name of the parent method to call
+ * @param paramCount The number of parameters to collect, or
+ * zero for a single argument from the body of ths element
+ * @param paramTypes The Java class names of the arguments
+ * (if you wish to use a primitive type, specify the corresonding
+ * Java wrapper class instead, such as <code>java.lang.Boolean</code>
+ * for a <code>boolean</code> parameter)
+ */
+ public CallMethodRule( int targetOffset,
+ String methodName,
+ int paramCount,
+ String paramTypes[]) {
+
+ this.targetOffset = targetOffset;
this.methodName = methodName;
this.paramCount = paramCount;
if (paramTypes == null) {
@@ -265,7 +327,35 @@
String methodName,
int paramCount,
Class paramTypes[]) {
+ this(0, methodName, paramCount, paramTypes);
+ }
+ /**
+ * Construct a "call method" rule with the specified method name and
+ * parameter types. If <code>paramCount</code> is set to zero the rule
+ * will use the body of this element as the single argument of the
+ * method, unless <code>paramTypes</code> is null or empty, in this
+ * case the rule will call the specified method with no arguments.
+ *
+ * @param targetOffset location of the target object. Positive numbers are
+ * relative to the top of the digester object stack. Negative numbers
+ * are relative to the bottom of the stack. Zero implies the top
+ * object on the stack.
+ * @param methodName Method name of the parent method to call
+ * @param paramCount The number of parameters to collect, or
+ * zero for a single argument from the body of ths element
+ * @param paramTypes The Java classes that represent the
+ * parameter types of the method arguments
+ * (if you wish to use a primitive type, specify the corresonding
+ * Java wrapper class instead, such as <code>java.lang.Boolean.TYPE</code>
+ * for a <code>boolean</code> parameter)
+ */
+ public CallMethodRule( int targetOffset,
+ String methodName,
+ int paramCount,
+ Class paramTypes[]) {
+
+ this.targetOffset = targetOffset;
this.methodName = methodName;
this.paramCount = paramCount;
if (paramTypes == null) {
@@ -292,6 +382,13 @@
protected String bodyText = null;
+ /**
+ * location of the target object for the call, relative to the
+ * top of the digester object stack. The default value of zero
+ * means the target object is the one on top of the stack.
+ */
+ private int targetOffset = 0;
+
/**
* The method name to call on the parent object.
*/
@@ -461,17 +558,33 @@
}
}
+ // Determine the target object for the method call
+ Object target;
+ if (targetOffset >= 0) {
+ target = digester.peek(targetOffset);
+ } else {
+ target = digester.peek( digester.getCount() + targetOffset );
+ }
+
+ if (target == null) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("[CallMethodRule]{");
+ sb.append(digester.match);
+ sb.append("} Call target is null (");
+ sb.append("targetOffset=");
+ sb.append(targetOffset);
+ sb.append(",stackdepth=");
+ sb.append(digester.getCount());
+ sb.append(")");
+ throw new org.xml.sax.SAXException(sb.toString());
+ }
+
// Invoke the required method on the top object
- Object top = digester.peek();
if (digester.log.isDebugEnabled()) {
StringBuffer sb = new StringBuffer("[CallMethodRule]{");
sb.append(digester.match);
sb.append("} Call ");
- if (top == null) {
- sb.append("[NULL TOP]");
- } else {
- sb.append(top.getClass().getName());
- }
+ sb.append(target.getClass().getName());
sb.append(".");
sb.append(methodName);
sb.append("(");
@@ -498,12 +611,12 @@
Object result = null;
if (useExactMatch) {
// invoke using exact match
- result = MethodUtils.invokeExactMethod(top, methodName,
+ result = MethodUtils.invokeExactMethod(target, methodName,
paramValues, paramTypes);
} else {
// invoke using fuzzier match
- result = MethodUtils.invokeMethod(top, methodName,
+ result = MethodUtils.invokeMethod(target, methodName,
paramValues, paramTypes);
}
1.13 +85 -3 jakarta-commons/digester/src/test/org/apache/commons/digester/CallMethodRuleTestCase.java
Index: CallMethodRuleTestCase.java
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/src/test/org/apache/commons/digester/CallMethodRuleTestCase.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- CallMethodRuleTestCase.java 18 Oct 2003 13:30:22 -0000 1.12
+++ CallMethodRuleTestCase.java 16 Feb 2004 02:26:38 -0000 1.13
@@ -593,6 +593,88 @@
assertEquals("Test beta property setting", "main/beta/epsilon/gamma" , bean.getBeta());
}
+
+ /**
+ * Test invoking an object which does not exist on the stack.
+ */
+ public void testCallInvalidTarget() throws Exception {
+
+ Digester digester = new Digester();
+ digester.addObjectCreate("employee", HashMap.class);
+
+ // there should be only one object on the stack (index zero),
+ // so selecting a target object with index 1 on the object stack
+ // should result in an exception.
+ CallMethodRule r = new CallMethodRule(1, "put", 0);
+ digester.addRule("employee", r);
+
+ try {
+ digester.parse(getInputStream("Test5.xml"));
+ fail("Exception should be thrown for invalid target offset");
+ }
+ catch(SAXException e) {
+ // ok, exception expected
+ }
+ }
+
+ /**
+ * Test invoking an object which is at top-1 on the stack, like
+ * SetNextRule does...
+ */
+ public void testCallNext() throws Exception {
+
+ Digester digester = new Digester();
+ digester.addObjectCreate("employee", HashMap.class);
+
+ digester.addObjectCreate("employee/address", Address.class);
+ digester.addSetNestedProperties("employee/address");
+ CallMethodRule r = new CallMethodRule(1, "put", 2);
+ digester.addRule("employee/address", r);
+ digester.addCallParam("employee/address/type", 0);
+ digester.addCallParam("employee/address", 1, 0);
+
+ HashMap map = (HashMap) digester.parse(getInputStream("Test5.xml"));
+
+ assertNotNull(map);
+ java.util.Set keys = map.keySet();
+ assertEquals(2, keys.size());
+ Address home = (Address) map.get("home");
+ assertNotNull(home);
+ assertEquals("HmZip", home.getZipCode());
+ Address office = (Address) map.get("office");
+ assertNotNull(office);
+ assertEquals("OfZip", office.getZipCode());
+ }
+
+ /**
+ * Test invoking an object which is at the root of the stack, like
+ * SetRoot does...
+ */
+ public void testCallRoot() throws Exception {
+
+ Digester digester = new Digester();
+ digester.addObjectCreate("employee", HashMap.class);
+
+ digester.addObjectCreate("employee/address", Address.class);
+ digester.addSetNestedProperties("employee/address");
+ CallMethodRule r = new CallMethodRule(-1, "put", 2);
+ digester.addRule("employee/address", r);
+ digester.addCallParam("employee/address/type", 0);
+ digester.addCallParam("employee/address", 1, 0);
+
+ HashMap map = (HashMap) digester.parse(getInputStream("Test5.xml"));
+
+ assertNotNull(map);
+ java.util.Set keys = map.keySet();
+ assertEquals(2, keys.size());
+ Address home = (Address) map.get("home");
+ assertNotNull(home);
+ assertEquals("HmZip", home.getZipCode());
+ Address office = (Address) map.get("office");
+ assertNotNull(office);
+ assertEquals("OfZip", office.getZipCode());
+ }
+
// ------------------------------------------------ Utility Support Methods
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org