[prev in list] [next in list] [prev in thread] [next in thread]
List: jakarta-commons-dev
Subject: cvs commit: jakarta-commons/digester/src/test/org/apache/commons/digester CallMethodRuleTestCase.jav
From: rdonkin () apache ! org
Date: 2002-09-30 19:48:51
[Download RAW message or body]
rdonkin 2002/09/30 12:48:51
Modified: digester build.xml
digester/src/java/org/apache/commons/digester
CallMethodRule.java CallParamRule.java
Digester.java
digester/src/test/org/apache/commons/digester
RuleTestCase.java
Added: digester/src/test/org/apache/commons/digester
CallMethodRuleTestCase.java
Log:
Fix for issue #12756. This enhances digester by support for call param rules which \
take their values from the stack. Patch submitted by John Yu.
Revision Changes Path
1.28 +12 -1 jakarta-commons/digester/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/build.xml,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -r1.27 -r1.28
--- build.xml 13 Aug 2002 16:28:59 -0000 1.27
+++ build.xml 30 Sep 2002 19:48:50 -0000 1.28
@@ -249,6 +249,7 @@
test.matching,
test.matching.extended,
test.rule,
+ test.callmethod,
test.bpsr,
test.xmlrules
"
@@ -277,6 +278,16 @@
</java>
</target>
+
+ <target name="test.callmethod" depends="compile.tests"
+ description="Run tests for CallMethodRule and CallParamRule ...">
+ <echo message="Running Rule tests ..."/>
+ <java classname="${test.runner}" fork="yes"
+ failonerror="${test.failonerror}">
+ <arg value="org.apache.commons.digester.CallMethodRuleTestCase"/>
+ <classpath refid="test.classpath"/>
+ </java>
+ </target>
<target name="test.digester" depends="compile.tests"
description="Run basic Digester unit tests ...">
1.19 +18 -10 \
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.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- CallMethodRule.java 29 Jul 2002 21:05:15 -0000 1.18
+++ CallMethodRule.java 30 Sep 2002 19:48:50 -0000 1.19
@@ -372,7 +372,7 @@
// Push an array to capture the parameter values if necessary
if (paramCount > 0) {
- String parameters[] = new String[paramCount];
+ Object parameters[] = new Object[paramCount];
for (int i = 0; i < parameters.length; i++) {
parameters[i] = null;
}
@@ -402,10 +402,10 @@
public void end() throws Exception {
// Retrieve or construct the parameter values array
- String parameters[] = null;
+ Object parameters[] = null;
if (paramCount > 0) {
- parameters = (String[]) digester.popParams();
+ parameters = (Object[]) digester.popParams();
if (digester.log.isTraceEnabled()) {
for (int i=0,size=parameters.length;i<size;i++) {
@@ -431,7 +431,7 @@
return;
}
- parameters = new String[1];
+ parameters = new Object[1];
parameters[0] = bodyText;
if (paramTypes.length == 0) {
paramTypes = new Class[1];
@@ -441,10 +441,18 @@
}
// Construct the parameter values array we will need
+ // We only do the conversion if the param value is a String and
+ // the specified paramType is not String.
Object paramValues[] = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
- paramValues[i] =
- ConvertUtils.convert(parameters[i], paramTypes[i]);
+ if(parameters[i] instanceof String &&
+ !String.class.isAssignableFrom(paramTypes[i])) {
+
+ paramValues[i] =
+ ConvertUtils.convert((String) parameters[i], \
paramTypes[i]); + } else {
+ paramValues[i] = parameters[i];
+ }
}
// Invoke the required method on the top object
1.9 +67 -41 \
jakarta-commons/digester/src/java/org/apache/commons/digester/CallParamRule.java
Index: CallParamRule.java
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/CallParamRule.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- CallParamRule.java 24 Sep 2002 20:50:07 -0000 1.8
+++ CallParamRule.java 30 Sep 2002 19:48:50 -0000 1.9
@@ -69,9 +69,19 @@
/**
- * Rule implementation that saves a parameter from either an attribute of
- * this element, or from the element body, to be used in a call generated
- * by a surrounding CallMethodRule rule.
+ * <p>Rule implementation that saves a parameter for use by a surrounding
+ * <code>CallMethodRule<code>.</p>
+ *
+ * <p>This parameter may be:
+ * <ul>
+ * <li>from an attribute of the current element
+ * See {@link #CallParamRule(int paramIndex, String attributeName)}
+ * <li>from current the element body
+ * See {@link #CallParamRule(int paramIndex)}
+ * <li>from the top object on the stack.
+ * See {@link #CallParamRule(int paramIndex, boolean fromStack)}
+ * </ul>
+ * </p>
*
* @author Craig McClanahan
* @version $Revision$ $Date$
@@ -147,6 +157,19 @@
}
+ /**
+ * Construct a "call parameter" rule.
+ *
+ * @param paramIndex The zero-relative parameter number
+ * @param fromStack should this parameter be taken from the top of the stack?
+ */
+ public CallParamRule(int paramIndex, boolean fromStack) {
+
+ this.paramIndex = paramIndex;
+ this.fromStack = fromStack;
+
+ }
+
// ----------------------------------------------------- Instance Variables
@@ -157,15 +180,15 @@
/**
- * The body text collected from this element.
+ * The zero-relative index of the parameter we are saving.
*/
- protected String bodyText = null;
+ protected int paramIndex = 0;
/**
- * The zero-relative index of the parameter we are saving.
+ * The position of the object from the top of the stack
*/
- protected int paramIndex = 0;
+ protected boolean fromStack = false;
// --------------------------------------------------------- Public Methods
@@ -178,12 +201,36 @@
*/
public void begin(Attributes attributes) throws Exception {
+ Object param = null;
+
if (attributeName != null) {
- bodyText = attributes.getValue(attributeName);
- String parameters[] = (String[]) digester.peekParams();
- parameters[paramIndex] = bodyText;
+
+ param = attributes.getValue(attributeName);
+
+ } else if(fromStack) {
+
+ param = digester.peek();
+
+ if (digester.log.isDebugEnabled()) {
+
+ StringBuffer sb = new StringBuffer("[CallParamRule]{");
+ sb.append(digester.match);
+ sb.append("} Save from stack; from stack?").append(fromStack);
+ sb.append("; object=").append(param);
+ digester.log.debug(sb.toString());
+ }
+ }
+
+ // Have to save the param object to the param stack frame here.
+ // Can't wait until end(). Otherwise, the object will be lost.
+ // We can't save the object as instance variables, as
+ // the instance variables will be overwritten
+ // if this CallParamRule is reused in subsequent nesting.
+
+ if(param != null) {
+ Object parameters[] = (Object[]) digester.peekParams();
+ parameters[paramIndex] = param;
}
-
}
@@ -194,36 +241,13 @@
*/
public void body(String bodyText) throws Exception {
- if (attributeName == null) {
- this.bodyText = bodyText.trim();
+ if (attributeName == null && !fromStack) {
+ Object parameters[] = (Object[]) digester.peekParams();
+ parameters[paramIndex] = bodyText.trim();
}
}
-
- /**
- * Process the end of this element.
- */
- public void end() throws Exception {
-
- if (attributeName == null) {
- String parameters[] = (String[]) digester.peekParams();
- parameters[paramIndex] = bodyText;
- }
-
- }
-
-
- /**
- * Clean up after parsing is complete.
- */
- public void finish() throws Exception {
-
- bodyText = null;
-
- }
-
-
/**
* Render a printable version of this Rule.
*/
@@ -234,6 +258,8 @@
sb.append(paramIndex);
sb.append(", attributeName=");
sb.append(attributeName);
+ sb.append(", from stack=");
+ sb.append(fromStack);
sb.append("]");
return (sb.toString());
1.67 +20 -4 \
jakarta-commons/digester/src/java/org/apache/commons/digester/Digester.java
Index: Digester.java
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/Digester.java,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- Digester.java 20 Aug 2002 02:51:46 -0000 1.66
+++ Digester.java 30 Sep 2002 19:48:50 -0000 1.67
@@ -1799,6 +1799,22 @@
/**
+ * Add a "call parameter" rule.
+ * This will either take a parameter from the stack
+ * or from the current element body text.
+ *
+ * @param paramIndex The zero-relative parameter number
+ * @param fromStack Should the call parameter be taken from the top of the \
stack? + */
+ public void addCallParam(String pattern, int paramIndex, boolean fromStack) {
+
+ addRule(pattern,
+ new CallParamRule(paramIndex, fromStack));
+
+ }
+
+
+ /**
* Add a "factory create" rule for the specified parameters.
*
* @param pattern Element matching pattern
1.22 +4 -127 \
jakarta-commons/digester/src/test/org/apache/commons/digester/RuleTestCase.java
Index: RuleTestCase.java
===================================================================
RCS file: /home/cvs/jakarta-commons/digester/src/test/org/apache/commons/digester/RuleTestCase.java,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- RuleTestCase.java 24 Sep 2002 20:50:07 -0000 1.21
+++ RuleTestCase.java 30 Sep 2002 19:48:51 -0000 1.22
@@ -597,104 +597,6 @@
/**
- * Test method calls with the CallMethodRule rule. It should be possible
- * to call any accessible method of the object on the top of the stack,
- * even methods with no arguments.
- */
- public void testCallMethod() throws SAXException, IOException {
-
- // Configure the digester as required
- digester.addObjectCreate("employee", Employee.class);
- // try all syntax permutations
- digester.addCallMethod("employee", "toString", 0, (Class[])null);
- digester.addCallMethod("employee", "toString", 0, (String[])null);
- digester.addCallMethod("employee", "toString", 0, new Class[] {});
- digester.addCallMethod("employee", "toString", 0, new String[] {});
- digester.addCallMethod("employee", "toString");
-
- // Parse our test input
- Object root1 = null;
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test5.xml"));
-
- }
-
- /**
- * Test method calls with the CallMethodRule rule. It should be possible
- * to call any accessible method of the object on the top of the stack,
- * even methods with no arguments.
- */
- public void testCallMethod2() throws SAXException, IOException {
-
- //I was preparing this test case to fix another bug
- // i'll uncomment it once i've fixed it
-
- // Configure the digester as required
- digester.addObjectCreate("employee", Employee.class);
- // try all syntax permutations
- digester.addCallMethod("employee", "setLastName", 1,
- new String[] {"java.lang.String"});
- digester.addCallParam("employee/lastName", 0);
-
- // Parse our test input
- Object root1 = null;
-
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test5.xml"));
- Employee employee = (Employee) root1;
- assertEquals("Failed to call Employee.setLastName",
- "Last Name", employee.getLastName());
-
-
- digester = new Digester();
- // Configure the digester as required
- digester.addObjectCreate("employee", Employee.class);
- // try out primitive convertion
- digester.addCallMethod("employee", "setAge", 1,
- new Class[] {int.class});
- digester.addCallParam("employee/age", 0);
-
- // Parse our test input
- root1 = null;
-
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test5.xml"));
- employee = (Employee) root1;
- assertEquals("Failed to call Employee.setAge", 21, employee.getAge());
-
- digester = new Digester();
- // Configure the digester as required
- digester.addObjectCreate("employee", Employee.class);
- digester.addCallMethod("employee", "setActive", 1,
- new Class[] {boolean.class});
- digester.addCallParam("employee/active", 0);
-
- // Parse our test input
- root1 = null;
-
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test5.xml"));
- employee = (Employee) root1;
- assertEquals("Failed to call Employee.setActive",
- true, employee.isActive());
-
- digester = new Digester();
- // Configure the digester as required
- digester.addObjectCreate("employee", Employee.class);
- digester.addCallMethod("employee", "setSalary", 1,
- new Class[] {float.class});
- digester.addCallParam("employee/salary", 0);
-
- // Parse our test input
- root1 = null;
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test5.xml"));
- employee = (Employee) root1;
- assertEquals("Failed to call Employee.setSalary",
- 1000000.0f, employee.getSalary(), 0.1f);
- }
-
- /**
*/
public void testSetCustomProperties() throws SAXException, IOException {
@@ -830,29 +732,4 @@
}
- /**
- * Test nested CallMethod rules.
- */
- public void testCallMethod3() throws Exception {
-
- // Configure the digester as required
- StringBuffer word = new StringBuffer();
- digester.push(word);
- digester.addCallMethod("*/element", "append", 1);
- digester.addCallParam("*/element", 0, "name");
-
- // Parse our test input
- Object root1 = null;
- try {
- // an exception will be thrown if the method can't be found
- root1 = digester.parse(getInputStream("Test8.xml"));
-
- } catch (Throwable t) {
- // this means that the method can't be found and so the test fails
- fail("Digester threw Exception: " + t);
- }
-
- assertEquals("Wrong method call order", "ABA", word.toString());
-
- }
}
1.1 \
jakarta-commons/digester/src/test/org/apache/commons/digester/CallMethodRuleTestCase.java
Index: CallMethodRuleTestCase.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.commons.digester;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xml.sax.SAXException;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* <p>Tests for the <code>CallMethodRule</code> and associated
* <code>CallParamRule</code>.
*
* @author Christopher Lenz
*/
public class CallMethodRuleTestCase extends TestCase {
// ----------------------------------------------------- Instance Variables
/**
* The digester instance we will be processing.
*/
protected Digester digester = null;
// ----------------------------------------------------------- Constructors
/**
* Construct a new instance of this test case.
*
* @param name Name of the test case
*/
public CallMethodRuleTestCase(String name) {
super(name);
}
// --------------------------------------------------- Overall Test Methods
/**
* Set up instance variables required by this test case.
*/
public void setUp() {
digester = new Digester();
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() {
return (new TestSuite(CallMethodRuleTestCase.class));
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
digester = null;
}
// ------------------------------------------------ Individual Test Methods
/**
* Test method calls with the CallMethodRule rule. It should be possible
* to call any accessible method of the object on the top of the stack,
* even methods with no arguments.
*/
public void testBasic() throws SAXException, IOException {
// Configure the digester as required
digester.addObjectCreate("employee", Employee.class);
// try all syntax permutations
digester.addCallMethod("employee", "toString", 0, (Class[])null);
digester.addCallMethod("employee", "toString", 0, (String[])null);
digester.addCallMethod("employee", "toString", 0, new Class[] {});
digester.addCallMethod("employee", "toString", 0, new String[] {});
digester.addCallMethod("employee", "toString");
// Parse our test input
Object root1 = null;
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test5.xml"));
}
/**
* Test method calls with the CallMethodRule rule. It should be possible
* to call any accessible method of the object on the top of the stack,
* even methods with no arguments.
*/
public void testSettingProperties() throws SAXException, IOException {
// Configure the digester as required
digester.addObjectCreate("employee", Employee.class);
// try all syntax permutations
digester.addCallMethod("employee", "setLastName", 1,
new String[] {"java.lang.String"});
digester.addCallParam("employee/lastName", 0);
// Parse our test input
Object root1 = null;
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test5.xml"));
Employee employee = (Employee) root1;
assertEquals("Failed to call Employee.setLastName",
"Last Name", employee.getLastName());
digester = new Digester();
// Configure the digester as required
digester.addObjectCreate("employee", Employee.class);
// try out primitive convertion
digester.addCallMethod("employee", "setAge", 1,
new Class[] {int.class});
digester.addCallParam("employee/age", 0);
// Parse our test input
root1 = null;
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test5.xml"));
employee = (Employee) root1;
assertEquals("Failed to call Employee.setAge", 21, employee.getAge());
digester = new Digester();
// Configure the digester as required
digester.addObjectCreate("employee", Employee.class);
digester.addCallMethod("employee", "setActive", 1,
new Class[] {boolean.class});
digester.addCallParam("employee/active", 0);
// Parse our test input
root1 = null;
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test5.xml"));
employee = (Employee) root1;
assertEquals("Failed to call Employee.setActive",
true, employee.isActive());
digester = new Digester();
// Configure the digester as required
digester.addObjectCreate("employee", Employee.class);
digester.addCallMethod("employee", "setSalary", 1,
new Class[] {float.class});
digester.addCallParam("employee/salary", 0);
// Parse our test input
root1 = null;
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test5.xml"));
employee = (Employee) root1;
assertEquals("Failed to call Employee.setSalary",
1000000.0f, employee.getSalary(), 0.1f);
}
/**
* This tests the call methods params enhancement that provides
* for more complex stack-based calls.
*/
public void testParamsFromStack() throws SAXException, IOException {
StringBuffer xml = new StringBuffer().
append("<?xml version='1.0'?>").
append("<map>").
append(" <key name='The key'/>").
append(" <value name='The value'/>").
append("</map>");
digester.addObjectCreate("map", HashMap.class);
digester.addCallMethod("map", "put", 2);
digester.addObjectCreate("map/key", AlphaBean.class);
digester.addSetProperties("map/key");
digester.addCallParam("map/key", 0, true);
digester.addObjectCreate("map/value", BetaBean.class);
digester.addSetProperties("map/value");
digester.addCallParam("map/value", 1, true);
Map map = (Map) digester.parse(new StringReader(xml.toString()));
assertNotNull(map);
assertEquals(1, map.size());
assertEquals("The key",
((AlphaBean)map.keySet().iterator().next()).getName());
assertEquals("The value",
((BetaBean)map.values().iterator().next()).getName());
}
/**
* Test nested CallMethod rules.
*/
public void testOrderNested() throws Exception {
// Configure the digester as required
StringBuffer word = new StringBuffer();
digester.push(word);
digester.addCallMethod("*/element", "append", 1);
digester.addCallParam("*/element", 0, "name");
// Parse our test input
Object root1 = null;
try {
// an exception will be thrown if the method can't be found
root1 = digester.parse(getInputStream("Test8.xml"));
} catch (Throwable t) {
// this means that the method can't be found and so the test fails
fail("Digester threw Exception: " + t);
}
assertEquals("Wrong method call order", "ABA", word.toString());
}
// ------------------------------------------------ Utility Support Methods
/**
* Return an appropriate InputStream for the specified test file (which
* must be inside our current package.
*
* @param name Name of the test file we want
*
* @exception IOException if an input/output error occurs
*/
protected InputStream getInputStream(String name) throws IOException {
return (this.getClass().getResourceAsStream
("/org/apache/commons/digester/" + name));
}
}
--
To unsubscribe, e-mail: <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic