java blog jAbLoK

... řekněte Javě Ja!

/** * @author Pavel Kolesnikov * @date 5.12.2004 v 10:32 */

... v podstatě formalita?

aneb nebojme se výjimek

Na Intervalu jsem zahlédl článek o autentizaci pomocí filtrů — a v něm mě zaujal následující obrat:

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
chain.doFilter((ServletRequest) new MyHttpRequest((HttpServletRequest) request), response);
}
}

A následoval autorův komentář:

Nejprve zjistíme, jestli je příchozí požadavek typu HttpServletRequest (v podstatě formalita)...

Variace takovéhoto uvažování už byly tepány mnohkrát, ale zjevně málo.

O co jde?

Autor kódu tuší výjimku, a veden dobrým úmyslem se jí prachsprostě vyhne. V tomto případě přetypovává ServletRequest na HttpServletRequest, a proto se ujistí, že žádoucí kód bude volán pouze pro HttpServletRequest — nejspíše proto, že se obává "ošklivé" ClassCastException.

Jenže co když k takto eliminované výjimce dojde? V případě z Intervalu se zpracování požadavku tiše zastaví a volajícímu klientovi se vrátí nulový výstup.

Řeknete si — kód je stejně určen pro webové aplikace a k volání bez HttpServletRequestu nedojde. Dobrá, ale tím spíše nás nezabije, pokud v takovémto případě necháme vyskočit ClassCastException, případně si explicitně postěžujeme nějakým assertem. Fungování programu za správých okolností to neohrozí, a pokud ke spuštění kódu dojde za nesprávných podmínek (jakkoli takovouto situaci považujeme za nepravděpodobnou), nebude to fungovat tak jako tak, ale aspoň si člověk dřív všimne, že někde nastal problém.

Extrémní, názornou a bohužel ne zcela zřídkavou variantou obcházení výjimek je pak následující kód, který je občas k vidění:

try {
// ... nejaky kod
} catch (Exception e) {}

A jak to vypadá v praxi?

Abych nezůstal u planého teoretizování, přihodím předvčerejší zážitek s Xdocletem (nástroj pro generování konfiguračních souborů z Javadocových komentářů — viz xdoclet.sf.net.

Připsal jsem do projektu nový JSP tag, je jedno co dělal, podstatné bylo, že byl potomkem tagu z jiného projektu. Třída byla vkusně opatřena patřičnými Xdocletovými metadaty, spouštím ant — a nic. Vygenerovaný TLD obsahuje všechny tagy kromě čerstvě vytvořeného. Kontroluju task v build.xml — jasně je uvedeno, že se má taglib descriptor vygenerovat ze všech zdrojáků v daném adresáři, které končí na *Tag.java.

Zapínám v Xdocletu "výmluvný mód" (tedy verbose) — a nic.

Po zoufalé hodince marných snah hledánim překlepů počínaje a pokusy o programátorskou magii konče jsem si povšiml, že když nový tag neextenduje mou třídu, ale přímo TagSupport, tak se TLD vygeneruje. A bingo — v cestě onoho xdocletového tasku chyběla knihovna s původním extendovaným tagem. A autor příslušné části Xdocletu — nejspíše, aby programátora nevylekal ošklivou výjimkou — tento problém v naprosté tichosti ignoroval, zdroják s chybějící cestou něžně přeskočil a v klidu si generovál dál.

Tak tudy prosím opravdu ne :)