Oops - "direct *c*all behavior" :) Donnie
> -----Original Message----- > From: Donnie Hale [mailto:[EMAIL PROTECTED]] > 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:[EMAIL PROTECTED]] > > 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 <[EMAIL PROTECTED]> > > >>> Reply-To: Jakarta Commons Developers List > > >> <[EMAIL PROTECTED]> > > >>> To: Jakarta Commons Developers List <[EMAIL PROTECTED]> > > >>> 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 <[EMAIL PROTECTED]> > > >>>> Reply-To: Jakarta Commons Developers List > > >> <[EMAIL PROTECTED]> > > >>>> To: [EMAIL PROTECTED] > > >>>> 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: > > >>> <mailto:[EMAIL PROTECTED]> > > >>>> For additional commands, e-mail: > > >>> <mailto:[EMAIL PROTECTED]> > > >>>> > > >>>> > > >>> > > >>> > > >>> -- > > >>> To unsubscribe, e-mail: > > >>> <mailto:[EMAIL PROTECTED]> > > >>> For additional commands, e-mail: > > >>> <mailto:[EMAIL PROTECTED]> > > >>> > > >>> > > >>> > > >>> -- > > >>> To unsubscribe, e-mail: > > >> <mailto:[EMAIL PROTECTED]> > > >>> For additional commands, e-mail: > > >> <mailto:[EMAIL PROTECTED]> > > >>> > > >>> > > >> > > >> > > >> -- > > >> To unsubscribe, e-mail: > > >> <mailto:[EMAIL PROTECTED]> > > >> For additional commands, e-mail: > > >> <mailto:[EMAIL PROTECTED]> > > >> > > >> > > > > > > > > > -- > > > To unsubscribe, e-mail: > <mailto:[EMAIL PROTECTED]. > > org> > > For additional commands, e-mail: <mailto:[EMAIL PROTECTED]. > org> > -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]> -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]> -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>