Marc, himself, his blogs, and you reading them.

April 15, 2004
Exceptional bonus track

Here is a little trick I recently used to 'lift an exception over an interface'. A showing example of exception handling getting a bit hacky sometimes.

The interface at hand provides a call-back for processing a specific entry in a list. The list is type-aware, and the internal processAll avoids having the iterator and type-cast logic duplicated over all processors.


public class MyList {
    private final List entries= new ArrayList();

    public Entry get(int index) { return (Entry)this.entries.get(index); }
    public void add(Entry entry) { return this.entries.add(entry); }

    public static class Entry {
         // whatever builds up an Entry...
    }


    public static interface EntryProcessor() {
         public void process(Entry entry, int index);
    }

    public void processAll(EntryProcessor proc) {
        Iterator iterator = this.entries.iterator();
        int ndx=0;
        while (iterator.hasNext()) {
            Entry entry = (Entry) iterator.next();
            proc.process(entry, ndx++);
        }
    }
}

The EntryProcessor interface is lean and mean, nothing can go wrong can there? Well, I had to change my mind on that when I wanted to use the EntryProcessor approach to generate an XML listing (through SAX) of all the entries, by repeatedly calling a method that generates the SAXEvents for one entry... Something along these lines:


    ContentHandler ch;
    MyList allEntries;
...

    public void generateEntriesDocument() throws SAXException {
        ch.startDocument();
        generateAllEntries();
        ch.endDocument();
    }
   
...
    public void generateEntry(Entry entry) throws SAXException {
        ch.startElement(.....);
        ...
        ch.endElement(.....);
    }


In the listing above the generateAllEntries is missing since it's the actual subject of this posting. Let's try to see the challenge first. If I start iterating over the call to generateEntry() then I can get some SAXExceptions. And that's not a real problem since I do this in the context of the generateEntriesDocument() which declared the same exception so it can easily propagate onwards up the stack.

The problem comes however that when I use the processAll() and EntryProcessor interface to handle that iteration. Logically my process() implementation would just be a call to generateEntry(). Helas: given the no-exceptions-on-process() I'm obliged to choke up my SAXException from generateEntry(). Bummer.

I got out of the dillema by using an inner classes to (quite) easily lift the exception over the interface:


    public void generateAllEntries() throws SAXException() {
        final SAXException[] lifty = new SAXException[1];
        this.allEntries.processAll( new MyList.EntryProcessor(){
            public process(Entry entry, int ndx) {
                try{
                    generateEntry(entry);
                } catch (SAXException e) {
                    lifty[0] = e;
                }
            }
        });
        if (lifty[0] != null) throw lifty[0];
    }

And then I had a colleague pointing out the serious flaw in the above. This lifty guy is quite nifty, but he doesn't stop the interator that is running through the entries! We actually do need a RuntimeException to that goal


    public void generateAllEntries() throws SAXException() {
        try {
            this.allEntries.processAll( new MyList.EntryProcessor(){
                public process(Entry entry, int ndx) {
                    try{
                        generateEntry(entry);
                    } catch (SAXException e) {
                        throw new MyRuntimeException(e);
                    }
                }
            });
         } catch (MyRuntimeException re) {
              throw new (SaxException)re.getCause();
         }
    }

And given it some more thought in the end, I can't help thinking that some (checked) InterupptedProcessingException on the level of the process() and processAll() wouldn't have been all that bad.

# Posted by mpo at 02:05 PM | TrackBack
Comments
Post a comment









Remember personal info?





Please enter the security code you see here