You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Paul Brian Coleman <br...@cox.net> on 2006/01/16 18:57:01 UTC
[Digester] SetNextRule and NoSuchMethodException
I am apparently in need of a sanity check. I have written a very simple
XML document and would like to parse it using Jakarta Commons Digester.
I have followed some of the many examples available on the web and have
run into a problem with a SetNext Rule. The rule is not finding the
specified method on the parent object. This is unexpected because I
can do a digester.peek(1) to get the top-1 element on the stack and it
is the object I expected (Recipe) and do a digester.peek(0) to check the
type of the top element and it is the type I expected (Ingredient). I
can further verify that there is a method on the parent type that
matches the method specified in the SetNextRule and takes the type of
the top element as a parameter. As a further sanity test, I added a
catch block that examined the elements on the stack. As expected there
were only two elements - the parent and child objects I expected. I was
also able to use Class.getDeclaredMethods() method on the parent element
to verify that the method is there and public. (see method 10 in the
output below).
I am using:
- Java 5.0.5
- Commons Digester 1.7
- Commons BeanUtils 1.7
- Commons Collections 3.1
- Eclipse 3.1.1
- full strength coffee
Any ideas would be greatly appreciated.
Here is the XML document:
<recipe name="Vanilla Ice Cream" prepTime="15" cookTime="45">
<summary>The basic ice cream recipe</summary>
<ingredient>
<amount>.75</amount>
<unit>cups</unit>
<description>sugar</description>
</ingredient>
<preparationStep>Whisk eggs until fluffy</preparationStep>
</recipe>
Here is the relevant code for the parent class (Recipe)
package javaxmlplay;
import java.util.ArrayList;
import java.util.List;
public class Recipe {
private String summary;
private List ingredients;
private List preparationSteps;
private String name;
private int prepTime;
private int cookTime;
<. . . >
public void addIngredient( javaxmlplay.Ingredient newIngredient) {
if (null == this.ingredients) {
this.ingredients = new ArrayList();
}
this.ingredients.add(newIngredient);
}
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("Recipe: ");
buff.append("name=<" + this.name + ">");
buff.append("...");
return buff.toString();
}
}
Here is the very simple code for the child class (Ingredient):
package javaxmlplay;
public class Ingredient {
private double amount;
private String unit;
private String description;
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Ingredient: " );
buf.append("amount=<" + this.amount + ">");
buf.append("unit=<" + this.unit + ">");
buf.append("description=<" + this.description + ">");
return buf.toString();
}
}
Here is the code where I am having trouble:
package javaxmlplay;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.digester.Digester;
public class CommonsDigesterDemo {
public void digestIceCream() {
Digester digester = new Digester();
try {
// configure digester with rules for recipe
digester.setValidating(false);
digester.addObjectCreate("recipe", javaxmlplay.Recipe.class);
digester.addSetProperties("recipe");
digester.addBeanPropertySetter("recipe/summary");
digester.addObjectCreate("recipe/ingredient",
javaxmlplay.Ingredient.class);
digester.addBeanPropertySetter("recipe/ingredient/amount");
digester.addBeanPropertySetter("recipe/ingredient/unit");
digester.addBeanPropertySetter("recipe/ingredient/description");
digester.addSetNext("recipe/ingredient","
addIngredient");
// now read in the input file to be parsed
File inputFile = new File("config\\VanillaIceCream.xml");
// do the parsing and get back the recipe
Recipe recipe = (Recipe) digester.parse(inputFile);
System.out.println("The result is: " + recipe);
}
catch (Exception ex) {
System.out.println("Exception! " + ex);
System.out.println("stack top: " + digester.peek(0));
System.out.println("top-1: " + digester.peek(1));
System.out.println("size of stack: " + digester.getCount());
// debugging only
Ingredient ingredient = (Ingredient) digester.peek(0);
Recipe recipe = (Recipe) digester.peek(1);
Class recClass = recipe.getClass();
Method[] methods = recClass.getDeclaredMethods();
for (int i = 0 ; i < methods.length ; i++) {
System.out.println("method " + i + " : " + methods[i]);
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
CommonsDigesterDemo testInstance = new CommonsDigesterDemo();
testInstance.digestIceCream();
}
}
Here is some of the relevant output:
DEBUG [main] (Digester.java:1128) - Fire end() for
SetNextRule[methodName= addIngredient, paramType=null]
DEBUG [main] (SetNextRule.java:194) - [SetNextRule]{recipe/ingredient}
Call javaxmlplay.Recipe. addIngredient(Ingredient:
amount=<0.75>unit=<cups>description=<sugar>)
DEBUG [main] (MethodUtils.java:522) - Matching name= addIngredient on
class javaxmlplay.Recipe
DEBUG [main] (MethodUtils.java:662) - No match found.
ERROR [main] (Digester.java:1132) - End event threw exception
java.lang.NoSuchMethodException: No such accessible method:
addIngredient() on object: javaxmlplay.Recipe
at
org.apache.commons.beanutils.MethodUtils.invokeMethod(MethodUtils.java:214)
at org.apache.commons.digester.SetNextRule.end(SetNextRule.java:216)
at org.apache.commons.digester.Rule.end(Rule.java:230)
at org.apache.commons.digester.Digester.endElement(Digester.java:1130)
at
com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown
Source)
at
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown
Source)
at
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
Source)
at
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
at
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown
Source)
at
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown
Source)
at
com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at
com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown
Source)
at org.apache.commons.digester.Digester.parse(Digester.java:1631)
at
javaxmlplay.CommonsDigesterDemo.digestIceCream(CommonsDigesterDemo.java:39)
at javaxmlplay.CommonsDigesterDemo.main(CommonsDigesterDemo.java:92)
Exception! java.lang.NoSuchMethodException: No such accessible method:
addIngredient() on object: javaxmlplay.Recipe
stack top: Ingredient: amount=<0.75>unit=<cups>description=<sugar>
top-1: Recipe: name=<Vanilla Ice Cream>...
size of stack: 2
method 0 : public int javaxmlplay.Recipe.getCookTime()
method 1 : public void javaxmlplay.Recipe.setCookTime(int)
method 2 : public java.util.List javaxmlplay.Recipe.getIngredients()
method 3 : public void javaxmlplay.Recipe.setIngredients(java.util.List)
method 4 : public java.util.List javaxmlplay.Recipe.getPreparationSteps()
method 5 : public void
javaxmlplay.Recipe.setPreparationSteps(java.util.List)
method 6 : public int javaxmlplay.Recipe.getPrepTime()
method 7 : public void javaxmlplay.Recipe.setPrepTime(int)
method 8 : public java.lang.String javaxmlplay.Recipe.getSummary()
method 9 : public void javaxmlplay.Recipe.setSummary(java.lang.String)
method 10 : public void
javaxmlplay.Recipe.addIngredient(javaxmlplay.Ingredient) <<-- why
isn't Digester finding this?
method 11 : public void
javaxmlplay.Recipe.addPreparationStep(java.lang.String)
method 12 : public java.lang.String javaxmlplay.Recipe.getName()
method 13 : public java.lang.String javaxmlplay.Recipe.toString()
method 14 : public void javaxmlplay.Recipe.setName(java.lang.String)
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-user-help@jakarta.apache.org
Re: [Digester] SetNextRule and NoSuchMethodException
Posted by Paul Brian Coleman <br...@cox.net>.
Simon, it was indeed. I removed the extra space and everything started
to work perfectly. Ah, the joys of programming ;-)
Thanks!
Simon Kitching wrote:
>On Mon, 2006-01-16 at 12:57 -0500, Paul Brian Coleman wrote:
>
>
>> digester.addSetNext("recipe/ingredient","
>>addIngredient");
>>
>>
>
>Is that whitespace between the opening quote and the word addIngredient,
>ie " addIngredient"?
>
>
>
>>DEBUG [main] (MethodUtils.java:522) - Matching name= addIngredient on
>>
>>
>
>Looks like whitespace is there to me...
>
>The rest of the code looks ok to me, but if that's not the cause then
>I'll look again.
>
>Cheers,
>
>Simon
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: commons-user-help@jakarta.apache.org
>
>
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-user-help@jakarta.apache.org
Re: [Digester] SetNextRule and NoSuchMethodException
Posted by Simon Kitching <sk...@apache.org>.
On Mon, 2006-01-16 at 12:57 -0500, Paul Brian Coleman wrote:
> digester.addSetNext("recipe/ingredient","
> addIngredient");
Is that whitespace between the opening quote and the word addIngredient,
ie " addIngredient"?
> DEBUG [main] (MethodUtils.java:522) - Matching name= addIngredient on
Looks like whitespace is there to me...
The rest of the code looks ok to me, but if that's not the cause then
I'll look again.
Cheers,
Simon
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-user-help@jakarta.apache.org