You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Pierre Métras <ge...@sympatico.ca> on 2001/03/15 04:03:00 UTC

Digester bug, comments and enhancements

Hi,

It seems that Bugzilla didn't swallowed the incidents I opened yesterday (I
can't find them in Bugzilla queries), so I post them again in the list.

[1] Digester enhancement.
=================
I have set up a ObjectPushRule class that allows to have the digester use
existing objects, instead of creating new ones when it encounters a pattern.
For instance, you have two containers containA and containB that need to
collect objects when the digester encounters tags <a> or <b>. Now, you are
able to write:

containA = new ContainA();
containB = new ContainB();

// Put <a> objects into containA
digester.addObjectPush("*/a", containA);
 ... <a> processing
digester.addSetNext("*/a", "add");

// Put <b> objects into containB
digester.addObjectPush("*/b", containB);
... <b> processing
digester.addSetNext("*/b", "add");

and process an XML file with intermixed <a></a> and <b></b> tags:
    <a></a>
    <b></b>
    <a></a>
and have the containA object contain all the "a", and containB all the "b".

In order to fit with the rest of the digester engine (and because the
Digester is a final class), I've added a "addObjectPush" method.
The code for this is at the end of the e-mail.


[2] Digester bug
===========
As the Digester class uses a lot of BeanUtils and PropertyUtils methods,
would it be possible to correlate the Digester.setDebug() method to also
call the BeanUtils.setDebug().

Also, I think that the documentation should be improved to mention that ALL
the classes and the methods accessed by the Digester must be declared
public.

Consider the following short example:
class A
{
  int id;
  setId(int id) {
    this.id = id;
  }
}

class B extends A
{
  String name;
  setName(name) {
    this.name = name;
  }
}

In order for the digester to digest the tag <b id="1" name="foo" /> (with
the appropriate rules), you must have:
- setName public
- setId public
- class B public
AND class A public

If you forget to declare A public (as I did), you end up with a B object
partially initialized: "name" attribute is OK, but not "id". And no error
message or hint from the digester!!!

If you set the BeanUtils.setDebug(), then you obtain a "CANNOT HAPPEN:"
message printed by the "populate" method! It should be more pleasant to have
that method raise an exception when this occurs to facilitate the debugging,
instead of allowing a fuzzy situation...


[3] Digester enhancement
=================
In regard of the previous comment, could it be possible (after version 1.0
release) to parameterize the access control level of the digester, when
accessing methods.

I am presently working on a framework (not struts related) where I use the
digester to initialize the state of the framework. Later, I will have
clients classes built upon that framework.
In order to do the initialization of my objects, the digester imposes on me
to declare all the classes and setter methods as public. The risk is that
later, I open a breach in my objects and the clients classes will be able to
modify the state of the framework.

I think it would be cool to have either:
- a global flag to tell the digester that it can access private or protected
classes when accessing the setter methods.
- or better, on a rule by rule cases, define the access level authorized.


Pierre Métras

And now, the ObjectPushRule stuff:

= ObjectPushRule.java==================================
package org.apache.struts.digester;


import org.xml.sax.AttributeList;


/**
 * Rule implementation that pushes and existing object
 * onto the object stack.  When the element is complete, the
 * object will be popped
 *
 * @author Pierre Métras
 * @version $Revision: 1.0 $ $Date: 2001/03/10 23:18:29 $
 */

public final class ObjectPushRule extends Rule {


    // -----------------------------------------------------------
Constructors


    /**
     * Construct an object create rule with the specified class name.
     *
     * @param digester The associated Digester
     * @param object The object to push onto the stack
     */
    public ObjectPushRule(Digester digester, Object object) {

 super(digester);
 this.object = object;

    }



    // ----------------------------------------------------- Instance
Variables


    /**
     * The object put on top of the stack.
     */
    private Object object = null;



    // --------------------------------------------------------- Public
Methods


    /**
     * Process the beginning of this element.
     *
     * @param attributes The attribute list of this element
     */
    public void begin(AttributeList attributes) throws Exception {

 digester.push(object);

    }


    /**
     * Process the end of this element.
     */
    public void end() throws Exception {

 Object top = digester.pop();
 if (digester.getDebug() >= 1)
     digester.log("Pop " + top.getClass().getName());

    }


    /**
     * Clean up after parsing is complete.
     */
    public void finish() throws Exception {

 object = null;

    }

}

==================================================

=Digester.java========================================

    /**
     * Add an "object push" rule for the specified parameters.
     *
     * @param pattern Element matching pattern
     * @param object The object to be pushed onto the stack when the pattern
     * is recognized.
     */
    public void addObjectPush(String pattern, Object object) {

       addRule(pattern,
           new ObjectPushRule(this, object));

    }

==================================================