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