You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by "Craig R. McClanahan" <cr...@apache.org> on 2001/12/05 04:07:50 UTC

Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Hi Donnie,

IIRC, Digester only knows how to call public methods of public classes --
and an anonymous inner class isn't public.

Could you try two things for me?
* Try this under the Sun JDK just to see if the behavior is different
* Try this where the driver class is a regular public class,
  rather than an inner class

That will help us narrow down where the difficulty is.

Craig


On Tue, 4 Dec 2001, Donnie Hale wrote:

> Date: Tue, 4 Dec 2001 22:15:20 -0500
> From: Donnie Hale <do...@haleonline.net>
> Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> To: commons-dev@jakarta.apache.org
> Subject: Digester yielding IllegalAccessException in CallMethodRule,
>      SetNextRule
>
> I searched the list archives and didn't see anything directly on-topic.
> Sorry if I missed it. Also, this is likely a normal Java issue, but I'm not
> getting it. :(
>
> Here's a very pared down example which reproduces my problem exactly:
>
> // Driver.java
> public class Driver
> {
>     public static void main(String[] args)
>     {
>         try
>         {
>             Driver driver = new Driver();
>             driver.parseWebApp(new Reader());
>         }
>         catch (Exception e)
>         {
>             e.printStackTrace();
>         }
>     }
>
>     public void Driver()
>     {
>     }
>
>     public void parseWebApp(Reader reader) throws Exception
>     {
>         reader.digestWebXmlFile(
>             new Reader.WebXmlFileDigestion()
>             {
>                 public void parseError(Throwable t) throws Exception
>                 {
>                     t.printStackTrace();
>                 }
>
>                 public void setServletMapping(
>                     String servletName, String urlPattern)
>                 {
>                     addServletMapping(servletName, urlPattern);
>                 }
>             }
>         );
>     }
>
>     public void addServletMapping(String servletName, String urlPattern)
>     {
>         System.out.println("Mapping read: " + servletName + " => " +
> urlPattern);
>     }
> }
>
> // Reader.java
> import java.io.InputStream;
> import java.io.IOException;
> import java.net.URL;
> import org.xml.sax.Attributes;
> import org.xml.sax.SAXException;
> import org.apache.commons.digester.Digester;
> import org.apache.commons.digester.Rule;
>
> public class Reader
> {
>     public static interface WebXmlFileDigestion
>     {
>         public void parseError(Throwable t) throws Exception;
>
>         public void setServletMapping(String servletName, String
> urlPattern);
>     }
>
>     public void Reader()
>     {
>     }
>
>     public void digestWebXmlFile(WebXmlFileDigestion callback)
>         throws Exception
>     {
>         // Prepare a Digester to scan the web application deployment
> descriptor
>         Digester digester = new Digester();
>         digester.push(callback);
>         digester.setDebug(1);
>         digester.setNamespaceAware(true);
>         digester.setValidating(false);
>
>         // Register our local copy of the DTDs that we can find
>         for (int i = 0; i < registrations_.length; i += 2)
>         {
>             URL url = this.getClass().getResource(registrations_[i+1]);
>             if (url != null)
>             {
>                 digester.register(registrations_[i], url.toString());
>             }
>         }
>
>         // Configure the processing rules that we need
>         digester.addCallMethod("web-app/servlet-mapping",
>             "setServletMapping", 2);
>         digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
>         digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
>
>         InputStream input= null;
>         try
>         {
>             input = this.getClass().getResourceAsStream("web.xml");
>             digester.parse(input);
>         }
>         catch (Throwable e)
>         {
>             callback.parseError(e);
>         }
>         finally
>         {
>             if (input != null)
>             {
>                 input.close();
>             }
>         }
>     }
>
>     protected static final String registrations_[] =
>     {
>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
>         "/org/apache/struts/resources/web-app_2_2.dtd",
>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
>         "/org/apache/struts/resources/web-app_2_3.dtd"
>     };
> }
>
> The object on which the method call is to be invoked is an instance of an
> anonymous inner class which implements a public (nested) interface. All the
> methods on the interface and its anonymous implementation are public. All
> the methods on Driver and Reader are public. Yet when I run this, I get:
>
> java.lang.IllegalAccessException: Driver$1
>         at java.lang.reflect.Method.invoke(Native Method)
>         at
> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
>         at
> org.apache.commons.digester.Digester.endElement(Digester.java:757)
>         at
> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
>         at
> org.apache.xerces.validators.common.XMLValidator.callEndElement(XMLValidator
> .java:1480)
>         at
> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.dispatch(XM
> LDocumentScanner.java:1149)
>         at
> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocumentScanner.
> java:381)
>         at org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
>         at org.apache.commons.digester.Digester.parse(Digester.java:1206)
>         at Reader.digestWebXmlFile(Reader.java:53)
>         at Driver.parseWebApp(Driver.java:23)
>         at Driver.main(Driver.java:9)
>
> I'm guessing this has something to do with the "Driver$1" being the
> classname. But it sure seems like I've done stuff like this before, just
> possibly not through reflection. Do I have to go to the extreme of making
> the interface implementation non-anonymous to have any hope of getting this
> to work?
>
> BTW, I'm using IBM's JDK 1.3 on Win2K.
>
> Thanks much,
>
> Donnie
>
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by robert burrell donkin <ro...@mac.com>.
On Wednesday, December 5, 2001, at 06:02 PM, Craig R. McClanahan wrote:

<snip>

> The key is that the third argument to addSetNext() has to match the
> method's signature, because this is what is used to do the reflection
> lookup.  The object on the top of the stack (a StandardHost in the example
> above) need only be assignment-compatible with that signature for this to
> work.
>
> Is this the case you're talking about?

no. at the moment, you have to specify the third parameter in order to 
make the digestion work.
this isn't too much of limitation - once you know how to do it, it's just 
a bit of extra typing.

where it becomes a bit more restrictive is when you use a general matching 
rule (like '*'). for example you might have a naming scheme where all 
child objects are added by calling addChild on the parent. you can write a 
single general rule only when either each class has an addChild method 
that takes a specific interface (xxx.yyy.zzz.Child, say). In this case, 
you can use something like

digester.addSetNext("*", "addChild", "xxx.yyy.zzz.Child);

you can also write a single general rule if every object has an exactly 
matching addChild method. In this case you can use

digester.addSetNext("*", "addChild");

if your object model doesn't follow one of these two patterns, then even 
if each object has a method with the right name with an 
assignment-compatible parameter then the digestion won't work.


i'm not suggesting that this is killing functionality but it'd be nice to 
have if there was an appropriate method finder available...


>> jason came across a similar issue with his automatic mapper but it meant
>> that he ended up using indexed properties rather than calling an addXXX
>> method for children (since beanutils will find an indexed property but 
>> not
>> a name single parameter method). unfortunately, using indexed properties
>> means that writing a digester-powered version is not realistic.
>>
>> i was wondering whether code to do this kind of single parameter method
>> finding would fit as part of propertyutils.
>>
>
> PropertyUtils itself is focused only on finding property getters and
> setters.  But some general utility classes to make some of the really
> strange things with Java reflection easier to use (for example, finding a
> "compatible" Method rather than just an exact-match Method) would
> certainly fit into the overall "beanutils" package.

yes, you're right - PropertyUtils does seem like the wrong place. it does 
have a number of private utility methods which might be useful, i suppose 
that these could be moved out or given public access, though.

- robert


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

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

On Wed, 5 Dec 2001, robert burrell donkin wrote:

> Date: Wed, 5 Dec 2001 18:03:53 +0000
> From: robert burrell donkin <ro...@mac.com>
> Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
>      SetNextRule
>
> On Wednesday, December 5, 2001, at 06:40 AM, Craig R. McClanahan wrote:
>
> > On Tue, 4 Dec 2001, Donnie Hale wrote:
>
> <snip>
>
> >> Is it possible to
> >> implement an interface with methods which have package scope though the
> >> interface methods are public? I don't care that some unknown future
> >> entity
> >> implements the interface; but I don't want the methods in the
> >> implementation
> >> of it that I care about to be publicly accessible. My copy of the
> >> language
> >> spec is at work...
> >>
> >
> > I'm sure it's feasible to implement access via reflection (which is what
> > Digester uses) to methods defined public through an interface - we ran
> > into a similar case in BeanUtils and solved it be looking up an
> > appropriate java.lang.reflect.Method object correctly.  I'm not sure what
> > happens when you shadow a package-private method with a public one -- will
> > have to check on that.  However, AFAIK, the class itself has to be public
> > for any of this to work.
>
> hi craig
>
> this is sort of (tangentially) related to some stuff i was thinking about
> recently. betwixt (without any deep knowledge of the code - hopefully
> james will correct me if i'm wrong) has some code which does some wangling
> for this kind of case.
>
> at the moment the setNextRule (and other similar rules) uses reflection to
> call methods. it always looks for a method with an exact parameter match
> for the class it's going to pass in. this means that it won't find methods
> with the right name whose signature takes an interface implemented by the
> class or which takes a superclass. this isn't (usually) a big problem
> since the same functionality can be achieved by specifying the class but
> it is something that has confused new users. (i suppose that probably in
> this case, an improved method finder would have made a difference, though.
> )
>

We use Digester in the HEAD branch of Tomcat 4 to read server.xml and
web.xml files.  There are lots of cases where a public method takes an
interface, while the actual objects involved are specific implementation
instances, and things work fine -- like this (grossly simplified from
reality, but illustrating the point):

    public interface Container {
      ...
      public void addChild(Container child);
      ...
    }

    public class StandardEngine implements Container {
      ...
    }

    public class StandardHost implements Container {
      ...
    }

with Digester rules like:

    digester.addObjectCreate("Engine", "StandardEngine");
    digester.addSetProperties("Engine");
    digester.addObjectCreate("Engine/Host", "StandardHost");
    digester.addSetProperties("Engine/Host");
    digester.addSetNext("Engine/Host", "addChild", "Container");

The key is that the third argument to addSetNext() has to match the
method's signature, because this is what is used to do the reflection
lookup.  The object on the top of the stack (a StandardHost in the example
above) need only be assignment-compatible with that signature for this to
work.

Is this the case you're talking about?

> jason came across a similar issue with his automatic mapper but it meant
> that he ended up using indexed properties rather than calling an addXXX
> method for children (since beanutils will find an indexed property but not
> a name single parameter method). unfortunately, using indexed properties
> means that writing a digester-powered version is not realistic.
>
> i was wondering whether code to do this kind of single parameter method
> finding would fit as part of propertyutils.
>

PropertyUtils itself is focused only on finding property getters and
setters.  But some general utility classes to make some of the really
strange things with Java reflection easier to use (for example, finding a
"compatible" Method rather than just an exact-match Method) would
certainly fit into the overall "beanutils" package.

> - robert
>

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by robert burrell donkin <ro...@mac.com>.
On Wednesday, December 5, 2001, at 06:40 AM, Craig R. McClanahan wrote:

> On Tue, 4 Dec 2001, Donnie Hale wrote:

<snip>

>> Is it possible to
>> implement an interface with methods which have package scope though the
>> interface methods are public? I don't care that some unknown future 
>> entity
>> implements the interface; but I don't want the methods in the 
>> implementation
>> of it that I care about to be publicly accessible. My copy of the 
>> language
>> spec is at work...
>>
>
> I'm sure it's feasible to implement access via reflection (which is what
> Digester uses) to methods defined public through an interface - we ran
> into a similar case in BeanUtils and solved it be looking up an
> appropriate java.lang.reflect.Method object correctly.  I'm not sure what
> happens when you shadow a package-private method with a public one -- will
> have to check on that.  However, AFAIK, the class itself has to be public
> for any of this to work.

hi craig

this is sort of (tangentially) related to some stuff i was thinking about 
recently. betwixt (without any deep knowledge of the code - hopefully 
james will correct me if i'm wrong) has some code which does some wangling 
for this kind of case.

at the moment the setNextRule (and other similar rules) uses reflection to 
call methods. it always looks for a method with an exact parameter match 
for the class it's going to pass in. this means that it won't find methods 
with the right name whose signature takes an interface implemented by the 
class or which takes a superclass. this isn't (usually) a big problem 
since the same functionality can be achieved by specifying the class but 
it is something that has confused new users. (i suppose that probably in 
this case, an improved method finder would have made a difference, though.
)

jason came across a similar issue with his automatic mapper but it meant 
that he ended up using indexed properties rather than calling an addXXX 
method for children (since beanutils will find an indexed property but not 
a name single parameter method). unfortunately, using indexed properties 
means that writing a digester-powered version is not realistic.

i was wondering whether code to do this kind of single parameter method 
finding would fit as part of propertyutils.

- robert


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

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

On Sat, 8 Dec 2001, robert burrell donkin wrote:

> Date: Sat, 8 Dec 2001 13:33:29 +0000
> From: robert burrell donkin <ro...@mac.com>
> Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
>      SetNextRule
>
> i've played around the example code and craig's diagnosis seems to be
> correct (as usual :)
>
> the Method.getMethod used by digester returns the inner implementation
> which is only accessible within the package rather than the public
> interface implementation.
>
> this problem can be fixed - in my test harness - by using the
> PropertyUtils.getAccessibleMethod to find an accessible version of the
> method. unfortunately, this method is currently private in PropertyUtils.
> this is a method which is needed by PropertyUtils but doesn't really
> belong in there (it's a general method finder method rather than a
> property finder method).
>
> maybe the right thing to do would be to add a new class (in beanutils) -
> MethodUtils? - which would contain the general method-related methods from
> PropertyUtils and which exposed them as public methods. other utility
> method-related reflection methods could be added later. the public
> interface for PropertyUtils could be maintained but the private
> implementations would be moved into this new class. digester could them
> use the improved reflection methods in this new class.
>
> i'm willing to create patches if this plan is acceptable.
>

+1

> - robert
>

Craig

>
> On Thursday, December 6, 2001, at 02:04 AM, Donnie Hale wrote:
>
> > See below...
> >
> > Donnie
> >
> >
> >> -----Original Message-----
> >> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> >> R. McClanahan
> >> Sent: Wednesday, December 05, 2001 1:41 AM
> >> To: Jakarta Commons Developers List
> >> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
> >> SetNextRule
> >>
> >>
> >>
> >>
> >> On Tue, 4 Dec 2001, Donnie Hale wrote:
> >>
> >>> Date: Tue, 4 Dec 2001 22:44:09 -0500
> >>> From: Donnie Hale <do...@haleonline.net>
> >>> Reply-To: Jakarta Commons Developers List
> >> <co...@jakarta.apache.org>
> >>> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> >>> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
> >>>      SetNextRule
> >>>
> >>> Craig,
> >>>
> >>> Thanks for the prompt response. If I understand your second
> >> case, I tried
> >>> it, and it worked as I wanted:
> >>>
> >>> // Callback.java
> >>> public class Callback implements Reader.WebXmlFileDigestion
> >>> {
> >>>     public Callback(Driver d)
> >>>     {
> >>>         driver_ = d;
> >>>     }
> >>>
> >>>     public void parseError(Throwable t) throws Exception
> >>>     {
> >>>         t.printStackTrace();
> >>>     }
> >>>
> >>>     public void setServletMapping(
> >>>         String servletName, String urlPattern)
> >>>     {
> >>>         driver_.addServletMapping(servletName, urlPattern);
> >>>     }
> >>>
> >>>     Driver driver_;
> >>> }
> >>>
> >>> Then, in Driver.java, I used
> >>>
> >>>         reader.digestWebXmlFile(new Callback(this));
> >>>
> >>> instead of passing the anonymous implementing class.
> >>>
> >>
> >> OK, so we know it definitely has something to do with visibility of the
> >> called class.
> >>
> >>> I'll have to see if I have Sun's 1.3 JDK around to try. If not,
> >> it could be
> >>> a while, as I only have IDSL access. :)
> >>>
> >>> One more, related, thing, since you're in the know.
> >>
> >> I better be, since I wrote Digester :-).
> >>
> >>> Is it possible to
> >>> implement an interface with methods which have package scope though the
> >>> interface methods are public? I don't care that some unknown
> >> future entity
> >>> implements the interface; but I don't want the methods in the
> >> implementation
> >>> of it that I care about to be publicly accessible. My copy of
> >> the language
> >>> spec is at work...
> >>>
> >>
> >> I'm sure it's feasible to implement access via reflection (which is what
> >> Digester uses) to methods defined public through an interface - we ran
> >> into a similar case in BeanUtils and solved it be looking up an
> >> appropriate java.lang.reflect.Method object correctly.  I'm not sure what
> >> happens when you shadow a package-private method with a public one --
> >> will
> >> have to check on that.  However, AFAIK, the class itself has to be public
> >> for any of this to work.
> >
> > Is the requirement of the class being public an artifact of doing this
> > through reflection. If not, I don't understand. As an example, I've got
> > this
> > code in an app:
> >
> >         File dir = new File(dirName);
> >         String[] fileList = dir.list(
> >             new FilenameFilter()
> >             {
> >                 public boolean accept(java.io.File file, java.lang.String
> > name)
> >                 {
> >                     return name.toLowerCase().endsWith(fileSuffix);
> >                 }
> >             });
> >
> > Clearly, the File.list method needs an impl of FilenameFilter on which to
> > make callbacks. I'm providing it one, anonymously. I'm sure, though, that
> > the callback is direct - not via reflection. This works find for me.
> >
> > I guess that's my main source of confusion about the whole thing.
> >
> >
> >
> >>
> >>> Thanks much,
> >>>
> >>> Donnie
> >>>
> >>
> >> Craig
> >>
> >>
> >>>
> >>> -----Original Message-----
> >>> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> >>> R. McClanahan
> >>> Sent: Tuesday, December 04, 2001 10:08 PM
> >>> To: Jakarta Commons Developers List
> >>> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
> >>> SetNextRule
> >>>
> >>>
> >>> Hi Donnie,
> >>>
> >>> IIRC, Digester only knows how to call public methods of public
> >> classes --
> >>> and an anonymous inner class isn't public.
> >>>
> >>> Could you try two things for me?
> >>> * Try this under the Sun JDK just to see if the behavior is different
> >>> * Try this where the driver class is a regular public class,
> >>>   rather than an inner class
> >>>
> >>> That will help us narrow down where the difficulty is.
> >>>
> >>> Craig
> >>>
> >>>
> >>> On Tue, 4 Dec 2001, Donnie Hale wrote:
> >>>
> >>>> Date: Tue, 4 Dec 2001 22:15:20 -0500
> >>>> From: Donnie Hale <do...@haleonline.net>
> >>>> Reply-To: Jakarta Commons Developers List
> >> <co...@jakarta.apache.org>
> >>>> To: commons-dev@jakarta.apache.org
> >>>> Subject: Digester yielding IllegalAccessException in CallMethodRule,
> >>>>      SetNextRule
> >>>>
> >>>> I searched the list archives and didn't see anything directly
> >> on-topic.
> >>>> Sorry if I missed it. Also, this is likely a normal Java
> >> issue, but I'm
> >>> not
> >>>> getting it. :(
> >>>>
> >>>> Here's a very pared down example which reproduces my problem exactly:
> >>>>
> >>>> // Driver.java
> >>>> public class Driver
> >>>> {
> >>>>     public static void main(String[] args)
> >>>>     {
> >>>>         try
> >>>>         {
> >>>>             Driver driver = new Driver();
> >>>>             driver.parseWebApp(new Reader());
> >>>>         }
> >>>>         catch (Exception e)
> >>>>         {
> >>>>             e.printStackTrace();
> >>>>         }
> >>>>     }
> >>>>
> >>>>     public void Driver()
> >>>>     {
> >>>>     }
> >>>>
> >>>>     public void parseWebApp(Reader reader) throws Exception
> >>>>     {
> >>>>         reader.digestWebXmlFile(
> >>>>             new Reader.WebXmlFileDigestion()
> >>>>             {
> >>>>                 public void parseError(Throwable t) throws Exception
> >>>>                 {
> >>>>                     t.printStackTrace();
> >>>>                 }
> >>>>
> >>>>                 public void setServletMapping(
> >>>>                     String servletName, String urlPattern)
> >>>>                 {
> >>>>                     addServletMapping(servletName, urlPattern);
> >>>>                 }
> >>>>             }
> >>>>         );
> >>>>     }
> >>>>
> >>>>     public void addServletMapping(String servletName, String
> >> urlPattern)
> >>>>     {
> >>>>         System.out.println("Mapping read: " + servletName + " => " +
> >>>> urlPattern);
> >>>>     }
> >>>> }
> >>>>
> >>>> // Reader.java
> >>>> import java.io.InputStream;
> >>>> import java.io.IOException;
> >>>> import java.net.URL;
> >>>> import org.xml.sax.Attributes;
> >>>> import org.xml.sax.SAXException;
> >>>> import org.apache.commons.digester.Digester;
> >>>> import org.apache.commons.digester.Rule;
> >>>>
> >>>> public class Reader
> >>>> {
> >>>>     public static interface WebXmlFileDigestion
> >>>>     {
> >>>>         public void parseError(Throwable t) throws Exception;
> >>>>
> >>>>         public void setServletMapping(String servletName, String
> >>>> urlPattern);
> >>>>     }
> >>>>
> >>>>     public void Reader()
> >>>>     {
> >>>>     }
> >>>>
> >>>>     public void digestWebXmlFile(WebXmlFileDigestion callback)
> >>>>         throws Exception
> >>>>     {
> >>>>         // Prepare a Digester to scan the web application deployment
> >>>> descriptor
> >>>>         Digester digester = new Digester();
> >>>>         digester.push(callback);
> >>>>         digester.setDebug(1);
> >>>>         digester.setNamespaceAware(true);
> >>>>         digester.setValidating(false);
> >>>>
> >>>>         // Register our local copy of the DTDs that we can find
> >>>>         for (int i = 0; i < registrations_.length; i += 2)
> >>>>         {
> >>>>             URL url =
> >> this.getClass().getResource(registrations_[i+1]);
> >>>>             if (url != null)
> >>>>             {
> >>>>                 digester.register(registrations_[i], url.toString());
> >>>>             }
> >>>>         }
> >>>>
> >>>>         // Configure the processing rules that we need
> >>>>         digester.addCallMethod("web-app/servlet-mapping",
> >>>>             "setServletMapping", 2);
> >>>>
> >> digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
> >>>>
> >> digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
> >>>>
> >>>>         InputStream input= null;
> >>>>         try
> >>>>         {
> >>>>             input = this.getClass().getResourceAsStream("web.xml");
> >>>>             digester.parse(input);
> >>>>         }
> >>>>         catch (Throwable e)
> >>>>         {
> >>>>             callback.parseError(e);
> >>>>         }
> >>>>         finally
> >>>>         {
> >>>>             if (input != null)
> >>>>             {
> >>>>                 input.close();
> >>>>             }
> >>>>         }
> >>>>     }
> >>>>
> >>>>     protected static final String registrations_[] =
> >>>>     {
> >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
> >>>>         "/org/apache/struts/resources/web-app_2_2.dtd",
> >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
> >>>>         "/org/apache/struts/resources/web-app_2_3.dtd"
> >>>>     };
> >>>> }
> >>>>
> >>>> The object on which the method call is to be invoked is an
> >> instance of an
> >>>> anonymous inner class which implements a public (nested)
> >> interface. All
> >>> the
> >>>> methods on the interface and its anonymous implementation are
> >> public. All
> >>>> the methods on Driver and Reader are public. Yet when I run
> >> this, I get:
> >>>>
> >>>> java.lang.IllegalAccessException: Driver$1
> >>>>         at java.lang.reflect.Method.invoke(Native Method)
> >>>>         at
> >>>>
> >> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
> >>>>         at
> >>>> org.apache.commons.digester.Digester.endElement(Digester.java:757)
> >>>>         at
> >>>> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.validators.common.XMLValidator.callEndElement(XM
> >> LValidator
> >>>> .java:1480)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.d
> >> ispatch(XM
> >>>> LDocumentScanner.java:1149)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocume
> >> ntScanner.
> >>>> java:381)
> >>>>         at
> >>> org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
> >>>>         at
> >> org.apache.commons.digester.Digester.parse(Digester.java:1206)
> >>>>         at Reader.digestWebXmlFile(Reader.java:53)
> >>>>         at Driver.parseWebApp(Driver.java:23)
> >>>>         at Driver.main(Driver.java:9)
> >>>>
> >>>> I'm guessing this has something to do with the "Driver$1" being the
> >>>> classname. But it sure seems like I've done stuff like this
> >> before, just
> >>>> possibly not through reflection. Do I have to go to the
> >> extreme of making
> >>>> the interface implementation non-anonymous to have any hope of getting
> >>> this
> >>>> to work?
> >>>>
> >>>> BTW, I'm using IBM's JDK 1.3 on Win2K.
> >>>>
> >>>> Thanks much,
> >>>>
> >>>> Donnie
> >>>>
> >>>>
> >>>> --
> >>>> To unsubscribe, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>> For additional commands, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>>
> >>>>
> >>>
> >>>
> >>> --
> >>> To unsubscribe, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>> For additional commands, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>
> >>>
> >>>
> >>> --
> >>> To unsubscribe, e-mail:
> >> <ma...@jakarta.apache.org>
> >>> For additional commands, e-mail:
> >> <ma...@jakarta.apache.org>
> >>>
> >>>
> >>
> >>
> >> --
> >> To unsubscribe, e-mail:
> >> <ma...@jakarta.apache.org>
> >> For additional commands, e-mail:
> >> <ma...@jakarta.apache.org>
> >>
> >>
> >
> >
> > --
> > To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.
> > org>
> > For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.
> > org>
> >
>
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by robert burrell donkin <ro...@mac.com>.
hi donnie

i think that the code now in cvs should fix your problem.
could you give it a try?

- robert


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by Donnie Hale <do...@haleonline.net>.
Oops - "direct *c*all behavior" :)

Donnie


> -----Original Message-----
> From: Donnie Hale [mailto:donnie@haleonline.net]
> Sent: Saturday, December 08, 2001 12:09 PM
> To: Jakarta Commons Developers List
> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
> SetNextRule
>
>
> +1
>
> There's no reason, to my mind, that reflection-based behavior should be
> different than direct all behavior.
>
> Donnie
>
>
> > -----Original Message-----
> > From: robert burrell donkin [mailto:robertdonkin@mac.com]
> > Sent: Saturday, December 08, 2001 8:33 AM
> > To: Jakarta Commons Developers List
> > Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
> > SetNextRule
> >
> >
> > i've played around the example code and craig's diagnosis seems to be
> > correct (as usual :)
> >
> > the Method.getMethod used by digester returns the inner implementation
> > which is only accessible within the package rather than the public
> > interface implementation.
> >
> > this problem can be fixed - in my test harness - by using the
> > PropertyUtils.getAccessibleMethod to find an accessible version of the
> > method. unfortunately, this method is currently private in
> PropertyUtils.
> > this is a method which is needed by PropertyUtils but doesn't really
> > belong in there (it's a general method finder method rather than a
> > property finder method).
> >
> > maybe the right thing to do would be to add a new class (in beanutils) -
> > MethodUtils? - which would contain the general method-related
> > methods from
> > PropertyUtils and which exposed them as public methods. other utility
> > method-related reflection methods could be added later. the public
> > interface for PropertyUtils could be maintained but the private
> > implementations would be moved into this new class. digester could them
> > use the improved reflection methods in this new class.
> >
> > i'm willing to create patches if this plan is acceptable.
> >
> > - robert
> >
> >
> > On Thursday, December 6, 2001, at 02:04 AM, Donnie Hale wrote:
> >
> > > See below...
> > >
> > > Donnie
> > >
> > >
> > >> -----Original Message-----
> > >> From: craigmcc@localhost [mailto:craigmcc@localhost]On
> Behalf Of Craig
> > >> R. McClanahan
> > >> Sent: Wednesday, December 05, 2001 1:41 AM
> > >> To: Jakarta Commons Developers List
> > >> Subject: RE: Digester yielding IllegalAccessException in
> > CallMethodRule,
> > >> SetNextRule
> > >>
> > >>
> > >>
> > >>
> > >> On Tue, 4 Dec 2001, Donnie Hale wrote:
> > >>
> > >>> Date: Tue, 4 Dec 2001 22:44:09 -0500
> > >>> From: Donnie Hale <do...@haleonline.net>
> > >>> Reply-To: Jakarta Commons Developers List
> > >> <co...@jakarta.apache.org>
> > >>> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> > >>> Subject: RE: Digester yielding IllegalAccessException in
> > CallMethodRule,
> > >>>      SetNextRule
> > >>>
> > >>> Craig,
> > >>>
> > >>> Thanks for the prompt response. If I understand your second
> > >> case, I tried
> > >>> it, and it worked as I wanted:
> > >>>
> > >>> // Callback.java
> > >>> public class Callback implements Reader.WebXmlFileDigestion
> > >>> {
> > >>>     public Callback(Driver d)
> > >>>     {
> > >>>         driver_ = d;
> > >>>     }
> > >>>
> > >>>     public void parseError(Throwable t) throws Exception
> > >>>     {
> > >>>         t.printStackTrace();
> > >>>     }
> > >>>
> > >>>     public void setServletMapping(
> > >>>         String servletName, String urlPattern)
> > >>>     {
> > >>>         driver_.addServletMapping(servletName, urlPattern);
> > >>>     }
> > >>>
> > >>>     Driver driver_;
> > >>> }
> > >>>
> > >>> Then, in Driver.java, I used
> > >>>
> > >>>         reader.digestWebXmlFile(new Callback(this));
> > >>>
> > >>> instead of passing the anonymous implementing class.
> > >>>
> > >>
> > >> OK, so we know it definitely has something to do with
> visibility of the
> > >> called class.
> > >>
> > >>> I'll have to see if I have Sun's 1.3 JDK around to try. If not,
> > >> it could be
> > >>> a while, as I only have IDSL access. :)
> > >>>
> > >>> One more, related, thing, since you're in the know.
> > >>
> > >> I better be, since I wrote Digester :-).
> > >>
> > >>> Is it possible to
> > >>> implement an interface with methods which have package scope
> > though the
> > >>> interface methods are public? I don't care that some unknown
> > >> future entity
> > >>> implements the interface; but I don't want the methods in the
> > >> implementation
> > >>> of it that I care about to be publicly accessible. My copy of
> > >> the language
> > >>> spec is at work...
> > >>>
> > >>
> > >> I'm sure it's feasible to implement access via reflection
> > (which is what
> > >> Digester uses) to methods defined public through an
> interface - we ran
> > >> into a similar case in BeanUtils and solved it be looking up an
> > >> appropriate java.lang.reflect.Method object correctly.  I'm
> > not sure what
> > >> happens when you shadow a package-private method with a public one --
> > >> will
> > >> have to check on that.  However, AFAIK, the class itself has
> > to be public
> > >> for any of this to work.
> > >
> > > Is the requirement of the class being public an artifact of doing this
> > > through reflection. If not, I don't understand. As an
> example, I've got
> > > this
> > > code in an app:
> > >
> > >         File dir = new File(dirName);
> > >         String[] fileList = dir.list(
> > >             new FilenameFilter()
> > >             {
> > >                 public boolean accept(java.io.File file,
> > java.lang.String
> > > name)
> > >                 {
> > >                     return name.toLowerCase().endsWith(fileSuffix);
> > >                 }
> > >             });
> > >
> > > Clearly, the File.list method needs an impl of FilenameFilter
> > on which to
> > > make callbacks. I'm providing it one, anonymously. I'm sure,
> > though, that
> > > the callback is direct - not via reflection. This works find for me.
> > >
> > > I guess that's my main source of confusion about the whole thing.
> > >
> > >
> > >
> > >>
> > >>> Thanks much,
> > >>>
> > >>> Donnie
> > >>>
> > >>
> > >> Craig
> > >>
> > >>
> > >>>
> > >>> -----Original Message-----
> > >>> From: craigmcc@localhost [mailto:craigmcc@localhost]On
> Behalf Of Craig
> > >>> R. McClanahan
> > >>> Sent: Tuesday, December 04, 2001 10:08 PM
> > >>> To: Jakarta Commons Developers List
> > >>> Subject: Re: Digester yielding IllegalAccessException in
> > CallMethodRule,
> > >>> SetNextRule
> > >>>
> > >>>
> > >>> Hi Donnie,
> > >>>
> > >>> IIRC, Digester only knows how to call public methods of public
> > >> classes --
> > >>> and an anonymous inner class isn't public.
> > >>>
> > >>> Could you try two things for me?
> > >>> * Try this under the Sun JDK just to see if the behavior is
> different
> > >>> * Try this where the driver class is a regular public class,
> > >>>   rather than an inner class
> > >>>
> > >>> That will help us narrow down where the difficulty is.
> > >>>
> > >>> Craig
> > >>>
> > >>>
> > >>> On Tue, 4 Dec 2001, Donnie Hale wrote:
> > >>>
> > >>>> Date: Tue, 4 Dec 2001 22:15:20 -0500
> > >>>> From: Donnie Hale <do...@haleonline.net>
> > >>>> Reply-To: Jakarta Commons Developers List
> > >> <co...@jakarta.apache.org>
> > >>>> To: commons-dev@jakarta.apache.org
> > >>>> Subject: Digester yielding IllegalAccessException in
> CallMethodRule,
> > >>>>      SetNextRule
> > >>>>
> > >>>> I searched the list archives and didn't see anything directly
> > >> on-topic.
> > >>>> Sorry if I missed it. Also, this is likely a normal Java
> > >> issue, but I'm
> > >>> not
> > >>>> getting it. :(
> > >>>>
> > >>>> Here's a very pared down example which reproduces my
> problem exactly:
> > >>>>
> > >>>> // Driver.java
> > >>>> public class Driver
> > >>>> {
> > >>>>     public static void main(String[] args)
> > >>>>     {
> > >>>>         try
> > >>>>         {
> > >>>>             Driver driver = new Driver();
> > >>>>             driver.parseWebApp(new Reader());
> > >>>>         }
> > >>>>         catch (Exception e)
> > >>>>         {
> > >>>>             e.printStackTrace();
> > >>>>         }
> > >>>>     }
> > >>>>
> > >>>>     public void Driver()
> > >>>>     {
> > >>>>     }
> > >>>>
> > >>>>     public void parseWebApp(Reader reader) throws Exception
> > >>>>     {
> > >>>>         reader.digestWebXmlFile(
> > >>>>             new Reader.WebXmlFileDigestion()
> > >>>>             {
> > >>>>                 public void parseError(Throwable t) throws
> Exception
> > >>>>                 {
> > >>>>                     t.printStackTrace();
> > >>>>                 }
> > >>>>
> > >>>>                 public void setServletMapping(
> > >>>>                     String servletName, String urlPattern)
> > >>>>                 {
> > >>>>                     addServletMapping(servletName, urlPattern);
> > >>>>                 }
> > >>>>             }
> > >>>>         );
> > >>>>     }
> > >>>>
> > >>>>     public void addServletMapping(String servletName, String
> > >> urlPattern)
> > >>>>     {
> > >>>>         System.out.println("Mapping read: " + servletName
> + " => " +
> > >>>> urlPattern);
> > >>>>     }
> > >>>> }
> > >>>>
> > >>>> // Reader.java
> > >>>> import java.io.InputStream;
> > >>>> import java.io.IOException;
> > >>>> import java.net.URL;
> > >>>> import org.xml.sax.Attributes;
> > >>>> import org.xml.sax.SAXException;
> > >>>> import org.apache.commons.digester.Digester;
> > >>>> import org.apache.commons.digester.Rule;
> > >>>>
> > >>>> public class Reader
> > >>>> {
> > >>>>     public static interface WebXmlFileDigestion
> > >>>>     {
> > >>>>         public void parseError(Throwable t) throws Exception;
> > >>>>
> > >>>>         public void setServletMapping(String servletName, String
> > >>>> urlPattern);
> > >>>>     }
> > >>>>
> > >>>>     public void Reader()
> > >>>>     {
> > >>>>     }
> > >>>>
> > >>>>     public void digestWebXmlFile(WebXmlFileDigestion callback)
> > >>>>         throws Exception
> > >>>>     {
> > >>>>         // Prepare a Digester to scan the web application
> deployment
> > >>>> descriptor
> > >>>>         Digester digester = new Digester();
> > >>>>         digester.push(callback);
> > >>>>         digester.setDebug(1);
> > >>>>         digester.setNamespaceAware(true);
> > >>>>         digester.setValidating(false);
> > >>>>
> > >>>>         // Register our local copy of the DTDs that we can find
> > >>>>         for (int i = 0; i < registrations_.length; i += 2)
> > >>>>         {
> > >>>>             URL url =
> > >> this.getClass().getResource(registrations_[i+1]);
> > >>>>             if (url != null)
> > >>>>             {
> > >>>>                 digester.register(registrations_[i],
> url.toString());
> > >>>>             }
> > >>>>         }
> > >>>>
> > >>>>         // Configure the processing rules that we need
> > >>>>         digester.addCallMethod("web-app/servlet-mapping",
> > >>>>             "setServletMapping", 2);
> > >>>>
> > >> digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
> > >>>>
> > >> digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
> > >>>>
> > >>>>         InputStream input= null;
> > >>>>         try
> > >>>>         {
> > >>>>             input = this.getClass().getResourceAsStream("web.xml");
> > >>>>             digester.parse(input);
> > >>>>         }
> > >>>>         catch (Throwable e)
> > >>>>         {
> > >>>>             callback.parseError(e);
> > >>>>         }
> > >>>>         finally
> > >>>>         {
> > >>>>             if (input != null)
> > >>>>             {
> > >>>>                 input.close();
> > >>>>             }
> > >>>>         }
> > >>>>     }
> > >>>>
> > >>>>     protected static final String registrations_[] =
> > >>>>     {
> > >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
> > >>>>         "/org/apache/struts/resources/web-app_2_2.dtd",
> > >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
> > >>>>         "/org/apache/struts/resources/web-app_2_3.dtd"
> > >>>>     };
> > >>>> }
> > >>>>
> > >>>> The object on which the method call is to be invoked is an
> > >> instance of an
> > >>>> anonymous inner class which implements a public (nested)
> > >> interface. All
> > >>> the
> > >>>> methods on the interface and its anonymous implementation are
> > >> public. All
> > >>>> the methods on Driver and Reader are public. Yet when I run
> > >> this, I get:
> > >>>>
> > >>>> java.lang.IllegalAccessException: Driver$1
> > >>>>         at java.lang.reflect.Method.invoke(Native Method)
> > >>>>         at
> > >>>>
> > >>
> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
> > >>>>         at
> > >>>> org.apache.commons.digester.Digester.endElement(Digester.java:757)
> > >>>>         at
> > >>>> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
> > >>>>         at
> > >>>>
> > >>>
> > >> org.apache.xerces.validators.common.XMLValidator.callEndElement(XM
> > >> LValidator
> > >>>> .java:1480)
> > >>>>         at
> > >>>>
> > >>>
> > >> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.d
> > >> ispatch(XM
> > >>>> LDocumentScanner.java:1149)
> > >>>>         at
> > >>>>
> > >>>
> > >> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocume
> > >> ntScanner.
> > >>>> java:381)
> > >>>>         at
> > >>> org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
> > >>>>         at
> > >> org.apache.commons.digester.Digester.parse(Digester.java:1206)
> > >>>>         at Reader.digestWebXmlFile(Reader.java:53)
> > >>>>         at Driver.parseWebApp(Driver.java:23)
> > >>>>         at Driver.main(Driver.java:9)
> > >>>>
> > >>>> I'm guessing this has something to do with the "Driver$1" being the
> > >>>> classname. But it sure seems like I've done stuff like this
> > >> before, just
> > >>>> possibly not through reflection. Do I have to go to the
> > >> extreme of making
> > >>>> the interface implementation non-anonymous to have any hope
> > of getting
> > >>> this
> > >>>> to work?
> > >>>>
> > >>>> BTW, I'm using IBM's JDK 1.3 on Win2K.
> > >>>>
> > >>>> Thanks much,
> > >>>>
> > >>>> Donnie
> > >>>>
> > >>>>
> > >>>> --
> > >>>> To unsubscribe, e-mail:
> > >>> <ma...@jakarta.apache.org>
> > >>>> For additional commands, e-mail:
> > >>> <ma...@jakarta.apache.org>
> > >>>>
> > >>>>
> > >>>
> > >>>
> > >>> --
> > >>> To unsubscribe, e-mail:
> > >>> <ma...@jakarta.apache.org>
> > >>> For additional commands, e-mail:
> > >>> <ma...@jakarta.apache.org>
> > >>>
> > >>>
> > >>>
> > >>> --
> > >>> To unsubscribe, e-mail:
> > >> <ma...@jakarta.apache.org>
> > >>> For additional commands, e-mail:
> > >> <ma...@jakarta.apache.org>
> > >>>
> > >>>
> > >>
> > >>
> > >> --
> > >> To unsubscribe, e-mail:
> > >> <ma...@jakarta.apache.org>
> > >> For additional commands, e-mail:
> > >> <ma...@jakarta.apache.org>
> > >>
> > >>
> > >
> > >
> > > --
> > > To unsubscribe, e-mail:
> <mailto:commons-dev-unsubscribe@jakarta.apache.
> > org>
> > For additional commands, e-mail:
<mailto:commons-dev-help@jakarta.apache.
> org>
>


--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>



--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by Donnie Hale <do...@haleonline.net>.
+1

There's no reason, to my mind, that reflection-based behavior should be
different than direct all behavior.

Donnie


> -----Original Message-----
> From: robert burrell donkin [mailto:robertdonkin@mac.com]
> Sent: Saturday, December 08, 2001 8:33 AM
> To: Jakarta Commons Developers List
> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
> SetNextRule
>
>
> i've played around the example code and craig's diagnosis seems to be
> correct (as usual :)
>
> the Method.getMethod used by digester returns the inner implementation
> which is only accessible within the package rather than the public
> interface implementation.
>
> this problem can be fixed - in my test harness - by using the
> PropertyUtils.getAccessibleMethod to find an accessible version of the
> method. unfortunately, this method is currently private in PropertyUtils.
> this is a method which is needed by PropertyUtils but doesn't really
> belong in there (it's a general method finder method rather than a
> property finder method).
>
> maybe the right thing to do would be to add a new class (in beanutils) -
> MethodUtils? - which would contain the general method-related
> methods from
> PropertyUtils and which exposed them as public methods. other utility
> method-related reflection methods could be added later. the public
> interface for PropertyUtils could be maintained but the private
> implementations would be moved into this new class. digester could them
> use the improved reflection methods in this new class.
>
> i'm willing to create patches if this plan is acceptable.
>
> - robert
>
>
> On Thursday, December 6, 2001, at 02:04 AM, Donnie Hale wrote:
>
> > See below...
> >
> > Donnie
> >
> >
> >> -----Original Message-----
> >> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> >> R. McClanahan
> >> Sent: Wednesday, December 05, 2001 1:41 AM
> >> To: Jakarta Commons Developers List
> >> Subject: RE: Digester yielding IllegalAccessException in
> CallMethodRule,
> >> SetNextRule
> >>
> >>
> >>
> >>
> >> On Tue, 4 Dec 2001, Donnie Hale wrote:
> >>
> >>> Date: Tue, 4 Dec 2001 22:44:09 -0500
> >>> From: Donnie Hale <do...@haleonline.net>
> >>> Reply-To: Jakarta Commons Developers List
> >> <co...@jakarta.apache.org>
> >>> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> >>> Subject: RE: Digester yielding IllegalAccessException in
> CallMethodRule,
> >>>      SetNextRule
> >>>
> >>> Craig,
> >>>
> >>> Thanks for the prompt response. If I understand your second
> >> case, I tried
> >>> it, and it worked as I wanted:
> >>>
> >>> // Callback.java
> >>> public class Callback implements Reader.WebXmlFileDigestion
> >>> {
> >>>     public Callback(Driver d)
> >>>     {
> >>>         driver_ = d;
> >>>     }
> >>>
> >>>     public void parseError(Throwable t) throws Exception
> >>>     {
> >>>         t.printStackTrace();
> >>>     }
> >>>
> >>>     public void setServletMapping(
> >>>         String servletName, String urlPattern)
> >>>     {
> >>>         driver_.addServletMapping(servletName, urlPattern);
> >>>     }
> >>>
> >>>     Driver driver_;
> >>> }
> >>>
> >>> Then, in Driver.java, I used
> >>>
> >>>         reader.digestWebXmlFile(new Callback(this));
> >>>
> >>> instead of passing the anonymous implementing class.
> >>>
> >>
> >> OK, so we know it definitely has something to do with visibility of the
> >> called class.
> >>
> >>> I'll have to see if I have Sun's 1.3 JDK around to try. If not,
> >> it could be
> >>> a while, as I only have IDSL access. :)
> >>>
> >>> One more, related, thing, since you're in the know.
> >>
> >> I better be, since I wrote Digester :-).
> >>
> >>> Is it possible to
> >>> implement an interface with methods which have package scope
> though the
> >>> interface methods are public? I don't care that some unknown
> >> future entity
> >>> implements the interface; but I don't want the methods in the
> >> implementation
> >>> of it that I care about to be publicly accessible. My copy of
> >> the language
> >>> spec is at work...
> >>>
> >>
> >> I'm sure it's feasible to implement access via reflection
> (which is what
> >> Digester uses) to methods defined public through an interface - we ran
> >> into a similar case in BeanUtils and solved it be looking up an
> >> appropriate java.lang.reflect.Method object correctly.  I'm
> not sure what
> >> happens when you shadow a package-private method with a public one --
> >> will
> >> have to check on that.  However, AFAIK, the class itself has
> to be public
> >> for any of this to work.
> >
> > Is the requirement of the class being public an artifact of doing this
> > through reflection. If not, I don't understand. As an example, I've got
> > this
> > code in an app:
> >
> >         File dir = new File(dirName);
> >         String[] fileList = dir.list(
> >             new FilenameFilter()
> >             {
> >                 public boolean accept(java.io.File file,
> java.lang.String
> > name)
> >                 {
> >                     return name.toLowerCase().endsWith(fileSuffix);
> >                 }
> >             });
> >
> > Clearly, the File.list method needs an impl of FilenameFilter
> on which to
> > make callbacks. I'm providing it one, anonymously. I'm sure,
> though, that
> > the callback is direct - not via reflection. This works find for me.
> >
> > I guess that's my main source of confusion about the whole thing.
> >
> >
> >
> >>
> >>> Thanks much,
> >>>
> >>> Donnie
> >>>
> >>
> >> Craig
> >>
> >>
> >>>
> >>> -----Original Message-----
> >>> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> >>> R. McClanahan
> >>> Sent: Tuesday, December 04, 2001 10:08 PM
> >>> To: Jakarta Commons Developers List
> >>> Subject: Re: Digester yielding IllegalAccessException in
> CallMethodRule,
> >>> SetNextRule
> >>>
> >>>
> >>> Hi Donnie,
> >>>
> >>> IIRC, Digester only knows how to call public methods of public
> >> classes --
> >>> and an anonymous inner class isn't public.
> >>>
> >>> Could you try two things for me?
> >>> * Try this under the Sun JDK just to see if the behavior is different
> >>> * Try this where the driver class is a regular public class,
> >>>   rather than an inner class
> >>>
> >>> That will help us narrow down where the difficulty is.
> >>>
> >>> Craig
> >>>
> >>>
> >>> On Tue, 4 Dec 2001, Donnie Hale wrote:
> >>>
> >>>> Date: Tue, 4 Dec 2001 22:15:20 -0500
> >>>> From: Donnie Hale <do...@haleonline.net>
> >>>> Reply-To: Jakarta Commons Developers List
> >> <co...@jakarta.apache.org>
> >>>> To: commons-dev@jakarta.apache.org
> >>>> Subject: Digester yielding IllegalAccessException in CallMethodRule,
> >>>>      SetNextRule
> >>>>
> >>>> I searched the list archives and didn't see anything directly
> >> on-topic.
> >>>> Sorry if I missed it. Also, this is likely a normal Java
> >> issue, but I'm
> >>> not
> >>>> getting it. :(
> >>>>
> >>>> Here's a very pared down example which reproduces my problem exactly:
> >>>>
> >>>> // Driver.java
> >>>> public class Driver
> >>>> {
> >>>>     public static void main(String[] args)
> >>>>     {
> >>>>         try
> >>>>         {
> >>>>             Driver driver = new Driver();
> >>>>             driver.parseWebApp(new Reader());
> >>>>         }
> >>>>         catch (Exception e)
> >>>>         {
> >>>>             e.printStackTrace();
> >>>>         }
> >>>>     }
> >>>>
> >>>>     public void Driver()
> >>>>     {
> >>>>     }
> >>>>
> >>>>     public void parseWebApp(Reader reader) throws Exception
> >>>>     {
> >>>>         reader.digestWebXmlFile(
> >>>>             new Reader.WebXmlFileDigestion()
> >>>>             {
> >>>>                 public void parseError(Throwable t) throws Exception
> >>>>                 {
> >>>>                     t.printStackTrace();
> >>>>                 }
> >>>>
> >>>>                 public void setServletMapping(
> >>>>                     String servletName, String urlPattern)
> >>>>                 {
> >>>>                     addServletMapping(servletName, urlPattern);
> >>>>                 }
> >>>>             }
> >>>>         );
> >>>>     }
> >>>>
> >>>>     public void addServletMapping(String servletName, String
> >> urlPattern)
> >>>>     {
> >>>>         System.out.println("Mapping read: " + servletName + " => " +
> >>>> urlPattern);
> >>>>     }
> >>>> }
> >>>>
> >>>> // Reader.java
> >>>> import java.io.InputStream;
> >>>> import java.io.IOException;
> >>>> import java.net.URL;
> >>>> import org.xml.sax.Attributes;
> >>>> import org.xml.sax.SAXException;
> >>>> import org.apache.commons.digester.Digester;
> >>>> import org.apache.commons.digester.Rule;
> >>>>
> >>>> public class Reader
> >>>> {
> >>>>     public static interface WebXmlFileDigestion
> >>>>     {
> >>>>         public void parseError(Throwable t) throws Exception;
> >>>>
> >>>>         public void setServletMapping(String servletName, String
> >>>> urlPattern);
> >>>>     }
> >>>>
> >>>>     public void Reader()
> >>>>     {
> >>>>     }
> >>>>
> >>>>     public void digestWebXmlFile(WebXmlFileDigestion callback)
> >>>>         throws Exception
> >>>>     {
> >>>>         // Prepare a Digester to scan the web application deployment
> >>>> descriptor
> >>>>         Digester digester = new Digester();
> >>>>         digester.push(callback);
> >>>>         digester.setDebug(1);
> >>>>         digester.setNamespaceAware(true);
> >>>>         digester.setValidating(false);
> >>>>
> >>>>         // Register our local copy of the DTDs that we can find
> >>>>         for (int i = 0; i < registrations_.length; i += 2)
> >>>>         {
> >>>>             URL url =
> >> this.getClass().getResource(registrations_[i+1]);
> >>>>             if (url != null)
> >>>>             {
> >>>>                 digester.register(registrations_[i], url.toString());
> >>>>             }
> >>>>         }
> >>>>
> >>>>         // Configure the processing rules that we need
> >>>>         digester.addCallMethod("web-app/servlet-mapping",
> >>>>             "setServletMapping", 2);
> >>>>
> >> digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
> >>>>
> >> digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
> >>>>
> >>>>         InputStream input= null;
> >>>>         try
> >>>>         {
> >>>>             input = this.getClass().getResourceAsStream("web.xml");
> >>>>             digester.parse(input);
> >>>>         }
> >>>>         catch (Throwable e)
> >>>>         {
> >>>>             callback.parseError(e);
> >>>>         }
> >>>>         finally
> >>>>         {
> >>>>             if (input != null)
> >>>>             {
> >>>>                 input.close();
> >>>>             }
> >>>>         }
> >>>>     }
> >>>>
> >>>>     protected static final String registrations_[] =
> >>>>     {
> >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
> >>>>         "/org/apache/struts/resources/web-app_2_2.dtd",
> >>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
> >>>>         "/org/apache/struts/resources/web-app_2_3.dtd"
> >>>>     };
> >>>> }
> >>>>
> >>>> The object on which the method call is to be invoked is an
> >> instance of an
> >>>> anonymous inner class which implements a public (nested)
> >> interface. All
> >>> the
> >>>> methods on the interface and its anonymous implementation are
> >> public. All
> >>>> the methods on Driver and Reader are public. Yet when I run
> >> this, I get:
> >>>>
> >>>> java.lang.IllegalAccessException: Driver$1
> >>>>         at java.lang.reflect.Method.invoke(Native Method)
> >>>>         at
> >>>>
> >> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
> >>>>         at
> >>>> org.apache.commons.digester.Digester.endElement(Digester.java:757)
> >>>>         at
> >>>> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.validators.common.XMLValidator.callEndElement(XM
> >> LValidator
> >>>> .java:1480)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.d
> >> ispatch(XM
> >>>> LDocumentScanner.java:1149)
> >>>>         at
> >>>>
> >>>
> >> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocume
> >> ntScanner.
> >>>> java:381)
> >>>>         at
> >>> org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
> >>>>         at
> >> org.apache.commons.digester.Digester.parse(Digester.java:1206)
> >>>>         at Reader.digestWebXmlFile(Reader.java:53)
> >>>>         at Driver.parseWebApp(Driver.java:23)
> >>>>         at Driver.main(Driver.java:9)
> >>>>
> >>>> I'm guessing this has something to do with the "Driver$1" being the
> >>>> classname. But it sure seems like I've done stuff like this
> >> before, just
> >>>> possibly not through reflection. Do I have to go to the
> >> extreme of making
> >>>> the interface implementation non-anonymous to have any hope
> of getting
> >>> this
> >>>> to work?
> >>>>
> >>>> BTW, I'm using IBM's JDK 1.3 on Win2K.
> >>>>
> >>>> Thanks much,
> >>>>
> >>>> Donnie
> >>>>
> >>>>
> >>>> --
> >>>> To unsubscribe, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>> For additional commands, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>>
> >>>>
> >>>
> >>>
> >>> --
> >>> To unsubscribe, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>> For additional commands, e-mail:
> >>> <ma...@jakarta.apache.org>
> >>>
> >>>
> >>>
> >>> --
> >>> To unsubscribe, e-mail:
> >> <ma...@jakarta.apache.org>
> >>> For additional commands, e-mail:
> >> <ma...@jakarta.apache.org>
> >>>
> >>>
> >>
> >>
> >> --
> >> To unsubscribe, e-mail:
> >> <ma...@jakarta.apache.org>
> >> For additional commands, e-mail:
> >> <ma...@jakarta.apache.org>
> >>
> >>
> >
> >
> > --
> > To unsubscribe, e-mail:
<mailto:commons-dev-unsubscribe@jakarta.apache.
> org>
> For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.
> org>
>


--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by robert burrell donkin <ro...@mac.com>.
i've played around the example code and craig's diagnosis seems to be 
correct (as usual :)

the Method.getMethod used by digester returns the inner implementation 
which is only accessible within the package rather than the public 
interface implementation.

this problem can be fixed - in my test harness - by using the 
PropertyUtils.getAccessibleMethod to find an accessible version of the 
method. unfortunately, this method is currently private in PropertyUtils. 
this is a method which is needed by PropertyUtils but doesn't really 
belong in there (it's a general method finder method rather than a 
property finder method).

maybe the right thing to do would be to add a new class (in beanutils) - 
MethodUtils? - which would contain the general method-related methods from 
PropertyUtils and which exposed them as public methods. other utility 
method-related reflection methods could be added later. the public 
interface for PropertyUtils could be maintained but the private 
implementations would be moved into this new class. digester could them 
use the improved reflection methods in this new class.

i'm willing to create patches if this plan is acceptable.

- robert


On Thursday, December 6, 2001, at 02:04 AM, Donnie Hale wrote:

> See below...
>
> Donnie
>
>
>> -----Original Message-----
>> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
>> R. McClanahan
>> Sent: Wednesday, December 05, 2001 1:41 AM
>> To: Jakarta Commons Developers List
>> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
>> SetNextRule
>>
>>
>>
>>
>> On Tue, 4 Dec 2001, Donnie Hale wrote:
>>
>>> Date: Tue, 4 Dec 2001 22:44:09 -0500
>>> From: Donnie Hale <do...@haleonline.net>
>>> Reply-To: Jakarta Commons Developers List
>> <co...@jakarta.apache.org>
>>> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
>>> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
>>>      SetNextRule
>>>
>>> Craig,
>>>
>>> Thanks for the prompt response. If I understand your second
>> case, I tried
>>> it, and it worked as I wanted:
>>>
>>> // Callback.java
>>> public class Callback implements Reader.WebXmlFileDigestion
>>> {
>>>     public Callback(Driver d)
>>>     {
>>>         driver_ = d;
>>>     }
>>>
>>>     public void parseError(Throwable t) throws Exception
>>>     {
>>>         t.printStackTrace();
>>>     }
>>>
>>>     public void setServletMapping(
>>>         String servletName, String urlPattern)
>>>     {
>>>         driver_.addServletMapping(servletName, urlPattern);
>>>     }
>>>
>>>     Driver driver_;
>>> }
>>>
>>> Then, in Driver.java, I used
>>>
>>>         reader.digestWebXmlFile(new Callback(this));
>>>
>>> instead of passing the anonymous implementing class.
>>>
>>
>> OK, so we know it definitely has something to do with visibility of the
>> called class.
>>
>>> I'll have to see if I have Sun's 1.3 JDK around to try. If not,
>> it could be
>>> a while, as I only have IDSL access. :)
>>>
>>> One more, related, thing, since you're in the know.
>>
>> I better be, since I wrote Digester :-).
>>
>>> Is it possible to
>>> implement an interface with methods which have package scope though the
>>> interface methods are public? I don't care that some unknown
>> future entity
>>> implements the interface; but I don't want the methods in the
>> implementation
>>> of it that I care about to be publicly accessible. My copy of
>> the language
>>> spec is at work...
>>>
>>
>> I'm sure it's feasible to implement access via reflection (which is what
>> Digester uses) to methods defined public through an interface - we ran
>> into a similar case in BeanUtils and solved it be looking up an
>> appropriate java.lang.reflect.Method object correctly.  I'm not sure what
>> happens when you shadow a package-private method with a public one -- 
>> will
>> have to check on that.  However, AFAIK, the class itself has to be public
>> for any of this to work.
>
> Is the requirement of the class being public an artifact of doing this
> through reflection. If not, I don't understand. As an example, I've got 
> this
> code in an app:
>
>         File dir = new File(dirName);
>         String[] fileList = dir.list(
>             new FilenameFilter()
>             {
>                 public boolean accept(java.io.File file, java.lang.String
> name)
>                 {
>                     return name.toLowerCase().endsWith(fileSuffix);
>                 }
>             });
>
> Clearly, the File.list method needs an impl of FilenameFilter on which to
> make callbacks. I'm providing it one, anonymously. I'm sure, though, that
> the callback is direct - not via reflection. This works find for me.
>
> I guess that's my main source of confusion about the whole thing.
>
>
>
>>
>>> Thanks much,
>>>
>>> Donnie
>>>
>>
>> Craig
>>
>>
>>>
>>> -----Original Message-----
>>> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
>>> R. McClanahan
>>> Sent: Tuesday, December 04, 2001 10:08 PM
>>> To: Jakarta Commons Developers List
>>> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
>>> SetNextRule
>>>
>>>
>>> Hi Donnie,
>>>
>>> IIRC, Digester only knows how to call public methods of public
>> classes --
>>> and an anonymous inner class isn't public.
>>>
>>> Could you try two things for me?
>>> * Try this under the Sun JDK just to see if the behavior is different
>>> * Try this where the driver class is a regular public class,
>>>   rather than an inner class
>>>
>>> That will help us narrow down where the difficulty is.
>>>
>>> Craig
>>>
>>>
>>> On Tue, 4 Dec 2001, Donnie Hale wrote:
>>>
>>>> Date: Tue, 4 Dec 2001 22:15:20 -0500
>>>> From: Donnie Hale <do...@haleonline.net>
>>>> Reply-To: Jakarta Commons Developers List
>> <co...@jakarta.apache.org>
>>>> To: commons-dev@jakarta.apache.org
>>>> Subject: Digester yielding IllegalAccessException in CallMethodRule,
>>>>      SetNextRule
>>>>
>>>> I searched the list archives and didn't see anything directly
>> on-topic.
>>>> Sorry if I missed it. Also, this is likely a normal Java
>> issue, but I'm
>>> not
>>>> getting it. :(
>>>>
>>>> Here's a very pared down example which reproduces my problem exactly:
>>>>
>>>> // Driver.java
>>>> public class Driver
>>>> {
>>>>     public static void main(String[] args)
>>>>     {
>>>>         try
>>>>         {
>>>>             Driver driver = new Driver();
>>>>             driver.parseWebApp(new Reader());
>>>>         }
>>>>         catch (Exception e)
>>>>         {
>>>>             e.printStackTrace();
>>>>         }
>>>>     }
>>>>
>>>>     public void Driver()
>>>>     {
>>>>     }
>>>>
>>>>     public void parseWebApp(Reader reader) throws Exception
>>>>     {
>>>>         reader.digestWebXmlFile(
>>>>             new Reader.WebXmlFileDigestion()
>>>>             {
>>>>                 public void parseError(Throwable t) throws Exception
>>>>                 {
>>>>                     t.printStackTrace();
>>>>                 }
>>>>
>>>>                 public void setServletMapping(
>>>>                     String servletName, String urlPattern)
>>>>                 {
>>>>                     addServletMapping(servletName, urlPattern);
>>>>                 }
>>>>             }
>>>>         );
>>>>     }
>>>>
>>>>     public void addServletMapping(String servletName, String
>> urlPattern)
>>>>     {
>>>>         System.out.println("Mapping read: " + servletName + " => " +
>>>> urlPattern);
>>>>     }
>>>> }
>>>>
>>>> // Reader.java
>>>> import java.io.InputStream;
>>>> import java.io.IOException;
>>>> import java.net.URL;
>>>> import org.xml.sax.Attributes;
>>>> import org.xml.sax.SAXException;
>>>> import org.apache.commons.digester.Digester;
>>>> import org.apache.commons.digester.Rule;
>>>>
>>>> public class Reader
>>>> {
>>>>     public static interface WebXmlFileDigestion
>>>>     {
>>>>         public void parseError(Throwable t) throws Exception;
>>>>
>>>>         public void setServletMapping(String servletName, String
>>>> urlPattern);
>>>>     }
>>>>
>>>>     public void Reader()
>>>>     {
>>>>     }
>>>>
>>>>     public void digestWebXmlFile(WebXmlFileDigestion callback)
>>>>         throws Exception
>>>>     {
>>>>         // Prepare a Digester to scan the web application deployment
>>>> descriptor
>>>>         Digester digester = new Digester();
>>>>         digester.push(callback);
>>>>         digester.setDebug(1);
>>>>         digester.setNamespaceAware(true);
>>>>         digester.setValidating(false);
>>>>
>>>>         // Register our local copy of the DTDs that we can find
>>>>         for (int i = 0; i < registrations_.length; i += 2)
>>>>         {
>>>>             URL url =
>> this.getClass().getResource(registrations_[i+1]);
>>>>             if (url != null)
>>>>             {
>>>>                 digester.register(registrations_[i], url.toString());
>>>>             }
>>>>         }
>>>>
>>>>         // Configure the processing rules that we need
>>>>         digester.addCallMethod("web-app/servlet-mapping",
>>>>             "setServletMapping", 2);
>>>>
>> digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
>>>>
>> digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
>>>>
>>>>         InputStream input= null;
>>>>         try
>>>>         {
>>>>             input = this.getClass().getResourceAsStream("web.xml");
>>>>             digester.parse(input);
>>>>         }
>>>>         catch (Throwable e)
>>>>         {
>>>>             callback.parseError(e);
>>>>         }
>>>>         finally
>>>>         {
>>>>             if (input != null)
>>>>             {
>>>>                 input.close();
>>>>             }
>>>>         }
>>>>     }
>>>>
>>>>     protected static final String registrations_[] =
>>>>     {
>>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
>>>>         "/org/apache/struts/resources/web-app_2_2.dtd",
>>>>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
>>>>         "/org/apache/struts/resources/web-app_2_3.dtd"
>>>>     };
>>>> }
>>>>
>>>> The object on which the method call is to be invoked is an
>> instance of an
>>>> anonymous inner class which implements a public (nested)
>> interface. All
>>> the
>>>> methods on the interface and its anonymous implementation are
>> public. All
>>>> the methods on Driver and Reader are public. Yet when I run
>> this, I get:
>>>>
>>>> java.lang.IllegalAccessException: Driver$1
>>>>         at java.lang.reflect.Method.invoke(Native Method)
>>>>         at
>>>>
>> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
>>>>         at
>>>> org.apache.commons.digester.Digester.endElement(Digester.java:757)
>>>>         at
>>>> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
>>>>         at
>>>>
>>>
>> org.apache.xerces.validators.common.XMLValidator.callEndElement(XM
>> LValidator
>>>> .java:1480)
>>>>         at
>>>>
>>>
>> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.d
>> ispatch(XM
>>>> LDocumentScanner.java:1149)
>>>>         at
>>>>
>>>
>> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocume
>> ntScanner.
>>>> java:381)
>>>>         at
>>> org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
>>>>         at
>> org.apache.commons.digester.Digester.parse(Digester.java:1206)
>>>>         at Reader.digestWebXmlFile(Reader.java:53)
>>>>         at Driver.parseWebApp(Driver.java:23)
>>>>         at Driver.main(Driver.java:9)
>>>>
>>>> I'm guessing this has something to do with the "Driver$1" being the
>>>> classname. But it sure seems like I've done stuff like this
>> before, just
>>>> possibly not through reflection. Do I have to go to the
>> extreme of making
>>>> the interface implementation non-anonymous to have any hope of getting
>>> this
>>>> to work?
>>>>
>>>> BTW, I'm using IBM's JDK 1.3 on Win2K.
>>>>
>>>> Thanks much,
>>>>
>>>> Donnie
>>>>
>>>>
>>>> --
>>>> To unsubscribe, e-mail:
>>> <ma...@jakarta.apache.org>
>>>> For additional commands, e-mail:
>>> <ma...@jakarta.apache.org>
>>>>
>>>>
>>>
>>>
>>> --
>>> To unsubscribe, e-mail:
>>> <ma...@jakarta.apache.org>
>>> For additional commands, e-mail:
>>> <ma...@jakarta.apache.org>
>>>
>>>
>>>
>>> --
>>> To unsubscribe, e-mail:
>> <ma...@jakarta.apache.org>
>>> For additional commands, e-mail:
>> <ma...@jakarta.apache.org>
>>>
>>>
>>
>>
>> --
>> To unsubscribe, e-mail:
>> <ma...@jakarta.apache.org>
>> For additional commands, e-mail:
>> <ma...@jakarta.apache.org>
>>
>>
>
>
> --
> To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.
> org>
> For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.
> org>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by Donnie Hale <do...@haleonline.net>.
See below...

Donnie


> -----Original Message-----
> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> R. McClanahan
> Sent: Wednesday, December 05, 2001 1:41 AM
> To: Jakarta Commons Developers List
> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
> SetNextRule
>
>
>
>
> On Tue, 4 Dec 2001, Donnie Hale wrote:
>
> > Date: Tue, 4 Dec 2001 22:44:09 -0500
> > From: Donnie Hale <do...@haleonline.net>
> > Reply-To: Jakarta Commons Developers List
> <co...@jakarta.apache.org>
> > To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> > Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
> >      SetNextRule
> >
> > Craig,
> >
> > Thanks for the prompt response. If I understand your second
> case, I tried
> > it, and it worked as I wanted:
> >
> > // Callback.java
> > public class Callback implements Reader.WebXmlFileDigestion
> > {
> >     public Callback(Driver d)
> >     {
> >         driver_ = d;
> >     }
> >
> >     public void parseError(Throwable t) throws Exception
> >     {
> >         t.printStackTrace();
> >     }
> >
> >     public void setServletMapping(
> >         String servletName, String urlPattern)
> >     {
> >         driver_.addServletMapping(servletName, urlPattern);
> >     }
> >
> >     Driver driver_;
> > }
> >
> > Then, in Driver.java, I used
> >
> >         reader.digestWebXmlFile(new Callback(this));
> >
> > instead of passing the anonymous implementing class.
> >
>
> OK, so we know it definitely has something to do with visibility of the
> called class.
>
> > I'll have to see if I have Sun's 1.3 JDK around to try. If not,
> it could be
> > a while, as I only have IDSL access. :)
> >
> > One more, related, thing, since you're in the know.
>
> I better be, since I wrote Digester :-).
>
> > Is it possible to
> > implement an interface with methods which have package scope though the
> > interface methods are public? I don't care that some unknown
> future entity
> > implements the interface; but I don't want the methods in the
> implementation
> > of it that I care about to be publicly accessible. My copy of
> the language
> > spec is at work...
> >
>
> I'm sure it's feasible to implement access via reflection (which is what
> Digester uses) to methods defined public through an interface - we ran
> into a similar case in BeanUtils and solved it be looking up an
> appropriate java.lang.reflect.Method object correctly.  I'm not sure what
> happens when you shadow a package-private method with a public one -- will
> have to check on that.  However, AFAIK, the class itself has to be public
> for any of this to work.

Is the requirement of the class being public an artifact of doing this
through reflection. If not, I don't understand. As an example, I've got this
code in an app:

        File dir = new File(dirName);
        String[] fileList = dir.list(
            new FilenameFilter()
            {
                public boolean accept(java.io.File file, java.lang.String
name)
                {
                    return name.toLowerCase().endsWith(fileSuffix);
                }
            });

Clearly, the File.list method needs an impl of FilenameFilter on which to
make callbacks. I'm providing it one, anonymously. I'm sure, though, that
the callback is direct - not via reflection. This works find for me.

I guess that's my main source of confusion about the whole thing.



>
> > Thanks much,
> >
> > Donnie
> >
>
> Craig
>
>
> >
> > -----Original Message-----
> > From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> > R. McClanahan
> > Sent: Tuesday, December 04, 2001 10:08 PM
> > To: Jakarta Commons Developers List
> > Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
> > SetNextRule
> >
> >
> > Hi Donnie,
> >
> > IIRC, Digester only knows how to call public methods of public
> classes --
> > and an anonymous inner class isn't public.
> >
> > Could you try two things for me?
> > * Try this under the Sun JDK just to see if the behavior is different
> > * Try this where the driver class is a regular public class,
> >   rather than an inner class
> >
> > That will help us narrow down where the difficulty is.
> >
> > Craig
> >
> >
> > On Tue, 4 Dec 2001, Donnie Hale wrote:
> >
> > > Date: Tue, 4 Dec 2001 22:15:20 -0500
> > > From: Donnie Hale <do...@haleonline.net>
> > > Reply-To: Jakarta Commons Developers List
> <co...@jakarta.apache.org>
> > > To: commons-dev@jakarta.apache.org
> > > Subject: Digester yielding IllegalAccessException in CallMethodRule,
> > >      SetNextRule
> > >
> > > I searched the list archives and didn't see anything directly
> on-topic.
> > > Sorry if I missed it. Also, this is likely a normal Java
> issue, but I'm
> > not
> > > getting it. :(
> > >
> > > Here's a very pared down example which reproduces my problem exactly:
> > >
> > > // Driver.java
> > > public class Driver
> > > {
> > >     public static void main(String[] args)
> > >     {
> > >         try
> > >         {
> > >             Driver driver = new Driver();
> > >             driver.parseWebApp(new Reader());
> > >         }
> > >         catch (Exception e)
> > >         {
> > >             e.printStackTrace();
> > >         }
> > >     }
> > >
> > >     public void Driver()
> > >     {
> > >     }
> > >
> > >     public void parseWebApp(Reader reader) throws Exception
> > >     {
> > >         reader.digestWebXmlFile(
> > >             new Reader.WebXmlFileDigestion()
> > >             {
> > >                 public void parseError(Throwable t) throws Exception
> > >                 {
> > >                     t.printStackTrace();
> > >                 }
> > >
> > >                 public void setServletMapping(
> > >                     String servletName, String urlPattern)
> > >                 {
> > >                     addServletMapping(servletName, urlPattern);
> > >                 }
> > >             }
> > >         );
> > >     }
> > >
> > >     public void addServletMapping(String servletName, String
> urlPattern)
> > >     {
> > >         System.out.println("Mapping read: " + servletName + " => " +
> > > urlPattern);
> > >     }
> > > }
> > >
> > > // Reader.java
> > > import java.io.InputStream;
> > > import java.io.IOException;
> > > import java.net.URL;
> > > import org.xml.sax.Attributes;
> > > import org.xml.sax.SAXException;
> > > import org.apache.commons.digester.Digester;
> > > import org.apache.commons.digester.Rule;
> > >
> > > public class Reader
> > > {
> > >     public static interface WebXmlFileDigestion
> > >     {
> > >         public void parseError(Throwable t) throws Exception;
> > >
> > >         public void setServletMapping(String servletName, String
> > > urlPattern);
> > >     }
> > >
> > >     public void Reader()
> > >     {
> > >     }
> > >
> > >     public void digestWebXmlFile(WebXmlFileDigestion callback)
> > >         throws Exception
> > >     {
> > >         // Prepare a Digester to scan the web application deployment
> > > descriptor
> > >         Digester digester = new Digester();
> > >         digester.push(callback);
> > >         digester.setDebug(1);
> > >         digester.setNamespaceAware(true);
> > >         digester.setValidating(false);
> > >
> > >         // Register our local copy of the DTDs that we can find
> > >         for (int i = 0; i < registrations_.length; i += 2)
> > >         {
> > >             URL url =
> this.getClass().getResource(registrations_[i+1]);
> > >             if (url != null)
> > >             {
> > >                 digester.register(registrations_[i], url.toString());
> > >             }
> > >         }
> > >
> > >         // Configure the processing rules that we need
> > >         digester.addCallMethod("web-app/servlet-mapping",
> > >             "setServletMapping", 2);
> > >
> digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
> > >
> digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
> > >
> > >         InputStream input= null;
> > >         try
> > >         {
> > >             input = this.getClass().getResourceAsStream("web.xml");
> > >             digester.parse(input);
> > >         }
> > >         catch (Throwable e)
> > >         {
> > >             callback.parseError(e);
> > >         }
> > >         finally
> > >         {
> > >             if (input != null)
> > >             {
> > >                 input.close();
> > >             }
> > >         }
> > >     }
> > >
> > >     protected static final String registrations_[] =
> > >     {
> > >         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
> > >         "/org/apache/struts/resources/web-app_2_2.dtd",
> > >         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
> > >         "/org/apache/struts/resources/web-app_2_3.dtd"
> > >     };
> > > }
> > >
> > > The object on which the method call is to be invoked is an
> instance of an
> > > anonymous inner class which implements a public (nested)
> interface. All
> > the
> > > methods on the interface and its anonymous implementation are
> public. All
> > > the methods on Driver and Reader are public. Yet when I run
> this, I get:
> > >
> > > java.lang.IllegalAccessException: Driver$1
> > >         at java.lang.reflect.Method.invoke(Native Method)
> > >         at
> > >
> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
> > >         at
> > > org.apache.commons.digester.Digester.endElement(Digester.java:757)
> > >         at
> > > org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
> > >         at
> > >
> >
> org.apache.xerces.validators.common.XMLValidator.callEndElement(XM
> LValidator
> > > .java:1480)
> > >         at
> > >
> >
> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.d
> ispatch(XM
> > > LDocumentScanner.java:1149)
> > >         at
> > >
> >
> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocume
> ntScanner.
> > > java:381)
> > >         at
> > org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
> > >         at
> org.apache.commons.digester.Digester.parse(Digester.java:1206)
> > >         at Reader.digestWebXmlFile(Reader.java:53)
> > >         at Driver.parseWebApp(Driver.java:23)
> > >         at Driver.main(Driver.java:9)
> > >
> > > I'm guessing this has something to do with the "Driver$1" being the
> > > classname. But it sure seems like I've done stuff like this
> before, just
> > > possibly not through reflection. Do I have to go to the
> extreme of making
> > > the interface implementation non-anonymous to have any hope of getting
> > this
> > > to work?
> > >
> > > BTW, I'm using IBM's JDK 1.3 on Win2K.
> > >
> > > Thanks much,
> > >
> > > Donnie
> > >
> > >
> > > --
> > > To unsubscribe, e-mail:
> > <ma...@jakarta.apache.org>
> > > For additional commands, e-mail:
> > <ma...@jakarta.apache.org>
> > >
> > >
> >
> >
> > --
> > To unsubscribe, e-mail:
> > <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> > <ma...@jakarta.apache.org>
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> >
> >
>
>
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

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

On Tue, 4 Dec 2001, Donnie Hale wrote:

> Date: Tue, 4 Dec 2001 22:44:09 -0500
> From: Donnie Hale <do...@haleonline.net>
> Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> Subject: RE: Digester yielding IllegalAccessException in CallMethodRule,
>      SetNextRule
>
> Craig,
>
> Thanks for the prompt response. If I understand your second case, I tried
> it, and it worked as I wanted:
>
> // Callback.java
> public class Callback implements Reader.WebXmlFileDigestion
> {
>     public Callback(Driver d)
>     {
>         driver_ = d;
>     }
>
>     public void parseError(Throwable t) throws Exception
>     {
>         t.printStackTrace();
>     }
>
>     public void setServletMapping(
>         String servletName, String urlPattern)
>     {
>         driver_.addServletMapping(servletName, urlPattern);
>     }
>
>     Driver driver_;
> }
>
> Then, in Driver.java, I used
>
>         reader.digestWebXmlFile(new Callback(this));
>
> instead of passing the anonymous implementing class.
>

OK, so we know it definitely has something to do with visibility of the
called class.

> I'll have to see if I have Sun's 1.3 JDK around to try. If not, it could be
> a while, as I only have IDSL access. :)
>
> One more, related, thing, since you're in the know.

I better be, since I wrote Digester :-).

> Is it possible to
> implement an interface with methods which have package scope though the
> interface methods are public? I don't care that some unknown future entity
> implements the interface; but I don't want the methods in the implementation
> of it that I care about to be publicly accessible. My copy of the language
> spec is at work...
>

I'm sure it's feasible to implement access via reflection (which is what
Digester uses) to methods defined public through an interface - we ran
into a similar case in BeanUtils and solved it be looking up an
appropriate java.lang.reflect.Method object correctly.  I'm not sure what
happens when you shadow a package-private method with a public one -- will
have to check on that.  However, AFAIK, the class itself has to be public
for any of this to work.

> Thanks much,
>
> Donnie
>

Craig


>
> -----Original Message-----
> From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
> R. McClanahan
> Sent: Tuesday, December 04, 2001 10:08 PM
> To: Jakarta Commons Developers List
> Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
> SetNextRule
>
>
> Hi Donnie,
>
> IIRC, Digester only knows how to call public methods of public classes --
> and an anonymous inner class isn't public.
>
> Could you try two things for me?
> * Try this under the Sun JDK just to see if the behavior is different
> * Try this where the driver class is a regular public class,
>   rather than an inner class
>
> That will help us narrow down where the difficulty is.
>
> Craig
>
>
> On Tue, 4 Dec 2001, Donnie Hale wrote:
>
> > Date: Tue, 4 Dec 2001 22:15:20 -0500
> > From: Donnie Hale <do...@haleonline.net>
> > Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> > To: commons-dev@jakarta.apache.org
> > Subject: Digester yielding IllegalAccessException in CallMethodRule,
> >      SetNextRule
> >
> > I searched the list archives and didn't see anything directly on-topic.
> > Sorry if I missed it. Also, this is likely a normal Java issue, but I'm
> not
> > getting it. :(
> >
> > Here's a very pared down example which reproduces my problem exactly:
> >
> > // Driver.java
> > public class Driver
> > {
> >     public static void main(String[] args)
> >     {
> >         try
> >         {
> >             Driver driver = new Driver();
> >             driver.parseWebApp(new Reader());
> >         }
> >         catch (Exception e)
> >         {
> >             e.printStackTrace();
> >         }
> >     }
> >
> >     public void Driver()
> >     {
> >     }
> >
> >     public void parseWebApp(Reader reader) throws Exception
> >     {
> >         reader.digestWebXmlFile(
> >             new Reader.WebXmlFileDigestion()
> >             {
> >                 public void parseError(Throwable t) throws Exception
> >                 {
> >                     t.printStackTrace();
> >                 }
> >
> >                 public void setServletMapping(
> >                     String servletName, String urlPattern)
> >                 {
> >                     addServletMapping(servletName, urlPattern);
> >                 }
> >             }
> >         );
> >     }
> >
> >     public void addServletMapping(String servletName, String urlPattern)
> >     {
> >         System.out.println("Mapping read: " + servletName + " => " +
> > urlPattern);
> >     }
> > }
> >
> > // Reader.java
> > import java.io.InputStream;
> > import java.io.IOException;
> > import java.net.URL;
> > import org.xml.sax.Attributes;
> > import org.xml.sax.SAXException;
> > import org.apache.commons.digester.Digester;
> > import org.apache.commons.digester.Rule;
> >
> > public class Reader
> > {
> >     public static interface WebXmlFileDigestion
> >     {
> >         public void parseError(Throwable t) throws Exception;
> >
> >         public void setServletMapping(String servletName, String
> > urlPattern);
> >     }
> >
> >     public void Reader()
> >     {
> >     }
> >
> >     public void digestWebXmlFile(WebXmlFileDigestion callback)
> >         throws Exception
> >     {
> >         // Prepare a Digester to scan the web application deployment
> > descriptor
> >         Digester digester = new Digester();
> >         digester.push(callback);
> >         digester.setDebug(1);
> >         digester.setNamespaceAware(true);
> >         digester.setValidating(false);
> >
> >         // Register our local copy of the DTDs that we can find
> >         for (int i = 0; i < registrations_.length; i += 2)
> >         {
> >             URL url = this.getClass().getResource(registrations_[i+1]);
> >             if (url != null)
> >             {
> >                 digester.register(registrations_[i], url.toString());
> >             }
> >         }
> >
> >         // Configure the processing rules that we need
> >         digester.addCallMethod("web-app/servlet-mapping",
> >             "setServletMapping", 2);
> >         digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
> >         digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
> >
> >         InputStream input= null;
> >         try
> >         {
> >             input = this.getClass().getResourceAsStream("web.xml");
> >             digester.parse(input);
> >         }
> >         catch (Throwable e)
> >         {
> >             callback.parseError(e);
> >         }
> >         finally
> >         {
> >             if (input != null)
> >             {
> >                 input.close();
> >             }
> >         }
> >     }
> >
> >     protected static final String registrations_[] =
> >     {
> >         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
> >         "/org/apache/struts/resources/web-app_2_2.dtd",
> >         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
> >         "/org/apache/struts/resources/web-app_2_3.dtd"
> >     };
> > }
> >
> > The object on which the method call is to be invoked is an instance of an
> > anonymous inner class which implements a public (nested) interface. All
> the
> > methods on the interface and its anonymous implementation are public. All
> > the methods on Driver and Reader are public. Yet when I run this, I get:
> >
> > java.lang.IllegalAccessException: Driver$1
> >         at java.lang.reflect.Method.invoke(Native Method)
> >         at
> > org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
> >         at
> > org.apache.commons.digester.Digester.endElement(Digester.java:757)
> >         at
> > org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
> >         at
> >
> org.apache.xerces.validators.common.XMLValidator.callEndElement(XMLValidator
> > .java:1480)
> >         at
> >
> org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.dispatch(XM
> > LDocumentScanner.java:1149)
> >         at
> >
> org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocumentScanner.
> > java:381)
> >         at
> org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
> >         at org.apache.commons.digester.Digester.parse(Digester.java:1206)
> >         at Reader.digestWebXmlFile(Reader.java:53)
> >         at Driver.parseWebApp(Driver.java:23)
> >         at Driver.main(Driver.java:9)
> >
> > I'm guessing this has something to do with the "Driver$1" being the
> > classname. But it sure seems like I've done stuff like this before, just
> > possibly not through reflection. Do I have to go to the extreme of making
> > the interface implementation non-anonymous to have any hope of getting
> this
> > to work?
> >
> > BTW, I'm using IBM's JDK 1.3 on Win2K.
> >
> > Thanks much,
> >
> > Donnie
> >
> >
> > --
> > To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> >
> >
>
>
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
>
>
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Digester yielding IllegalAccessException in CallMethodRule, SetNextRule

Posted by Donnie Hale <do...@haleonline.net>.
Craig,

Thanks for the prompt response. If I understand your second case, I tried
it, and it worked as I wanted:

// Callback.java
public class Callback implements Reader.WebXmlFileDigestion
{
    public Callback(Driver d)
    {
        driver_ = d;
    }

    public void parseError(Throwable t) throws Exception
    {
        t.printStackTrace();
    }

    public void setServletMapping(
        String servletName, String urlPattern)
    {
        driver_.addServletMapping(servletName, urlPattern);
    }

    Driver driver_;
}

Then, in Driver.java, I used

        reader.digestWebXmlFile(new Callback(this));

instead of passing the anonymous implementing class.

I'll have to see if I have Sun's 1.3 JDK around to try. If not, it could be
a while, as I only have IDSL access. :)

One more, related, thing, since you're in the know. Is it possible to
implement an interface with methods which have package scope though the
interface methods are public? I don't care that some unknown future entity
implements the interface; but I don't want the methods in the implementation
of it that I care about to be publicly accessible. My copy of the language
spec is at work...

Thanks much,

Donnie


-----Original Message-----
From: craigmcc@localhost [mailto:craigmcc@localhost]On Behalf Of Craig
R. McClanahan
Sent: Tuesday, December 04, 2001 10:08 PM
To: Jakarta Commons Developers List
Subject: Re: Digester yielding IllegalAccessException in CallMethodRule,
SetNextRule


Hi Donnie,

IIRC, Digester only knows how to call public methods of public classes --
and an anonymous inner class isn't public.

Could you try two things for me?
* Try this under the Sun JDK just to see if the behavior is different
* Try this where the driver class is a regular public class,
  rather than an inner class

That will help us narrow down where the difficulty is.

Craig


On Tue, 4 Dec 2001, Donnie Hale wrote:

> Date: Tue, 4 Dec 2001 22:15:20 -0500
> From: Donnie Hale <do...@haleonline.net>
> Reply-To: Jakarta Commons Developers List <co...@jakarta.apache.org>
> To: commons-dev@jakarta.apache.org
> Subject: Digester yielding IllegalAccessException in CallMethodRule,
>      SetNextRule
>
> I searched the list archives and didn't see anything directly on-topic.
> Sorry if I missed it. Also, this is likely a normal Java issue, but I'm
not
> getting it. :(
>
> Here's a very pared down example which reproduces my problem exactly:
>
> // Driver.java
> public class Driver
> {
>     public static void main(String[] args)
>     {
>         try
>         {
>             Driver driver = new Driver();
>             driver.parseWebApp(new Reader());
>         }
>         catch (Exception e)
>         {
>             e.printStackTrace();
>         }
>     }
>
>     public void Driver()
>     {
>     }
>
>     public void parseWebApp(Reader reader) throws Exception
>     {
>         reader.digestWebXmlFile(
>             new Reader.WebXmlFileDigestion()
>             {
>                 public void parseError(Throwable t) throws Exception
>                 {
>                     t.printStackTrace();
>                 }
>
>                 public void setServletMapping(
>                     String servletName, String urlPattern)
>                 {
>                     addServletMapping(servletName, urlPattern);
>                 }
>             }
>         );
>     }
>
>     public void addServletMapping(String servletName, String urlPattern)
>     {
>         System.out.println("Mapping read: " + servletName + " => " +
> urlPattern);
>     }
> }
>
> // Reader.java
> import java.io.InputStream;
> import java.io.IOException;
> import java.net.URL;
> import org.xml.sax.Attributes;
> import org.xml.sax.SAXException;
> import org.apache.commons.digester.Digester;
> import org.apache.commons.digester.Rule;
>
> public class Reader
> {
>     public static interface WebXmlFileDigestion
>     {
>         public void parseError(Throwable t) throws Exception;
>
>         public void setServletMapping(String servletName, String
> urlPattern);
>     }
>
>     public void Reader()
>     {
>     }
>
>     public void digestWebXmlFile(WebXmlFileDigestion callback)
>         throws Exception
>     {
>         // Prepare a Digester to scan the web application deployment
> descriptor
>         Digester digester = new Digester();
>         digester.push(callback);
>         digester.setDebug(1);
>         digester.setNamespaceAware(true);
>         digester.setValidating(false);
>
>         // Register our local copy of the DTDs that we can find
>         for (int i = 0; i < registrations_.length; i += 2)
>         {
>             URL url = this.getClass().getResource(registrations_[i+1]);
>             if (url != null)
>             {
>                 digester.register(registrations_[i], url.toString());
>             }
>         }
>
>         // Configure the processing rules that we need
>         digester.addCallMethod("web-app/servlet-mapping",
>             "setServletMapping", 2);
>         digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
>         digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
>
>         InputStream input= null;
>         try
>         {
>             input = this.getClass().getResourceAsStream("web.xml");
>             digester.parse(input);
>         }
>         catch (Throwable e)
>         {
>             callback.parseError(e);
>         }
>         finally
>         {
>             if (input != null)
>             {
>                 input.close();
>             }
>         }
>     }
>
>     protected static final String registrations_[] =
>     {
>         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
>         "/org/apache/struts/resources/web-app_2_2.dtd",
>         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
>         "/org/apache/struts/resources/web-app_2_3.dtd"
>     };
> }
>
> The object on which the method call is to be invoked is an instance of an
> anonymous inner class which implements a public (nested) interface. All
the
> methods on the interface and its anonymous implementation are public. All
> the methods on Driver and Reader are public. Yet when I run this, I get:
>
> java.lang.IllegalAccessException: Driver$1
>         at java.lang.reflect.Method.invoke(Native Method)
>         at
> org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:308)
>         at
> org.apache.commons.digester.Digester.endElement(Digester.java:757)
>         at
> org.apache.xerces.parsers.SAXParser.endElement(SAXParser.java:1403)
>         at
>
org.apache.xerces.validators.common.XMLValidator.callEndElement(XMLValidator
> .java:1480)
>         at
>
org.apache.xerces.framework.XMLDocumentScanner$ContentDispatcher.dispatch(XM
> LDocumentScanner.java:1149)
>         at
>
org.apache.xerces.framework.XMLDocumentScanner.parseSome(XMLDocumentScanner.
> java:381)
>         at
org.apache.xerces.framework.XMLParser.parse(XMLParser.java:1081)
>         at org.apache.commons.digester.Digester.parse(Digester.java:1206)
>         at Reader.digestWebXmlFile(Reader.java:53)
>         at Driver.parseWebApp(Driver.java:23)
>         at Driver.main(Driver.java:9)
>
> I'm guessing this has something to do with the "Driver$1" being the
> classname. But it sure seems like I've done stuff like this before, just
> possibly not through reflection. Do I have to go to the extreme of making
> the interface implementation non-anonymous to have any hope of getting
this
> to work?
>
> BTW, I'm using IBM's JDK 1.3 on Win2K.
>
> Thanks much,
>
> Donnie
>
>
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>