You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Zach Thompson <za...@mthoodmedia.com> on 2001/03/13 03:12:09 UTC

Digester order of events

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");

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?

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.

Zach

Re: Digester order of events

Posted by Zach Thompson <za...@mthoodmedia.com>.
Sorry - I noticed a confusing mistake in my post.  I was never actually
calling "new SomeType()" - that's why there was no runtime error.

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();

    SomeType p;

>     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");
> 
> 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?
> 
> 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.
> 
> Zach

Re: Digester order of events

Posted by Zach Thompson <za...@mthoodmedia.com>.
Actually, there's a setter in MyBean (setProp) but no corresponding "prop"
attribute in the XML.  At runtime, the JVM can't find type SomeType, and
it looks like that causes Digester to not ever call setName().  If I
comment out the first 4 lines of the MyBean class (all the
SomeType/setProp stuff), things will work.  Also, if I add type SomeType
to my runtime CLASSPATH, things will work.  Please note that I had an error
in my original post: I never actually do "SomeType p = new SomeType();"
(that line should be "SomeType p;"), that's why there isn't a runtime error.

martin.cooper@tumbleweed.com wrote:
> Regarding your first point, are you saying "There's a name attribute in the 
> XML, but there's no corresponding setter, so the Digester should flag an 
> error"? If not, I apologise for putting words in your mouth. :-}
> 
> One of the nice things about the Digester is that I can tell it which 
> pieces of the XML I care about, and that's all it calls me about. If I 
> don't care about the value of a certain attribute, I shouldn't need to 
> provide for it. So I consider that a feature rather than a problem.
> 
> --
> Martin Cooper
> 
> At 06:12 PM 3/12/01, 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");
> >
> >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?
> >
> >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.
> >
> >Zach
> 
> 

Re: Digester order of events

Posted by ma...@tumbleweed.com.
Regarding your first point, are you saying "There's a name attribute in the 
XML, but there's no corresponding setter, so the Digester should flag an 
error"? If not, I apologise for putting words in your mouth. :-}

One of the nice things about the Digester is that I can tell it which 
pieces of the XML I care about, and that's all it calls me about. If I 
don't care about the value of a certain attribute, I shouldn't need to 
provide for it. So I consider that a feature rather than a problem.

--
Martin Cooper

At 06:12 PM 3/12/01, 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");
>
>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?
>
>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.
>
>Zach



Re: Digester order of events

Posted by "Craig R. McClanahan" <cr...@apache.org>.

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