On Mon, 12 Mar 2001, Zach Thompson wrote:

> Hello,
> 
> I just spent quite a bit of time debugging some code that uses a
> Digester, and I'd like to share what I found.
> 
> class MyBean {
>     SomeType p = new SomeType();
>     public void setProp(SomeType p) {
>         this.p = p;
>     }
> 
>     String name;
>     public void setName(String name) {
>         System.err.println("Setting name...");
>         this.name = name;
>     }
> }
> 
> ...
> 
> <mybean name="Fred"/>
> 
> ...
> 
> digester.addSetProperties("mybean");
>

Is the object on top of the stack (at runtime) a MyBean?  If it's not, and
if the object on top of the stack does not have a "name" property, your
rule will be silently ignored.

Typically, you would have an object create rule for each object, prior to
the set properties rule:

        digester.addObjectCreate("mybean", "MyBean");
        digester.addSetProperties("mybean");

to ensure that an object of the correct type is on top of the stack.
 
> The name property was never being set..
> 
> The problem was that SomeType was not in my runtime CLASSPATH, so even
> though setProp() is never called, and hence no runtime error occurs,
> Digester fails to ever call setName().  Of course, the error here is
> really mine, but I'd like to at least see Digester give some debugging
> messages (I had debug detail set to 999).
> 
> 2.  Next I was trying to get the body of a tag and set a bean property
> with the content:
> 
> <mybean name="Fred">Some content</mybean>
> 
> ...
> 
> digester.addSetProperties("mybean");
> digester.addCallMethod("mybean", "setBody", 0);
> digester.addSetNext("mybean", "addMyBean");
> 
> I discovered that at the point addMyBean() is called, setBody() has not
> been called yet.  I realize that I'm just setting up a Digester
> here (not actually doing the parsing), so I can imagine that the order of
> events is not really defined here.  However, it seems like the parsing
> should generally follow the order that I set up the Digester in.  Am I
> missing something?
> 

There are order dependencies on the order in which you make these calls,
but it is actually somewhat more subtle than "call in the order I add the
rules".  This is because adding a rule registers things that happen at the
*beginning* of an XML element, as well as at the *end* of the XML element.

To illustrate this, let's assume you do the following:

        digester.addObjectCreate("mybean", "com.mycompany.MyBean");
        digester.addSetProperties("mybean");
        digester.addCallMethod("mybean", "setBody", 0);
        digester.addSetNext("mybean", "addMyBean");

and you process the XML file:

        <mybean name="Fred">Some content</mybean>

So what actually happens?  First, the events that are registered for the
beginning of the element are executed, in the order you registered them:

* (ObjectCreateRule) Instantiate the new object, and put it
  on the top of the stack.
* (SetPropertiesRule) Call the matching property setters on
  the top object on the stack, passing the values of the corresponding
  attributes.
* (CallMethodRule) No events registered.  If you had specified >0 call
  parameters, an array to contain them would have been pushed on the
  stack, to be processed by CallParamRule rules.
* (SetNextRule) No events registered.


Next, the body content of the <mybean> element is saved away.

Finally, the events that are registered for the end of the element are
executed, in REVERSE order:

* (SetNextRule) Call the specified method on the next-to-top object
  on the stack, passing the top object on the stack as an argument.
* (CallMethodRule) Call the specified method, passing the saved body
  content.  If you had specified >0 parameters, this rule would have
  popped the parameters array off the stack first and passed it instead.
* (SetPropertiesRule) No events registered.
* (ObjectCreateRule) Pop the top object off the stack.

> Anyway, I'll look at the struts source and see if I can come up with
> suggestions or patches for struts-dev, but I thought I'd share this info
> in case it helps anyone.
> 

You can do all this yourself by utililzing a SAX parser, but the Digester
module does most of the bookkeeping for you.  You'll find it much easier
to program, once you get the hang of how it works.

If you have got ideas about how to explain this process better in the
documentation, I'm all ears.

> Zach
> 

Craig


Reply via email to