2015-01-13 12 views
6

Dire che sono che si occupa dicostretto a utilizzare un metodo API di libreria che genera una sorta di eccezione di base non descrittiva; per esempio "lancia Eccezione" in Java. Supponiamo che io non abbia la possibilità di modificare l'origine della libreria e che io debba gestire l'eccezione di base ogni volta che chiamo il metodo API dai miei metodi. Per alcuni contesto, il mio codice potrebbe essere simile senza l'intervento:Come affrontare l'eccezione di base generata dal metodo API?

public void myMethod() throws Exception { // I don't want to do this. 
    someAPIObject.theirMethod(); // API method throwing base exception. 
} 

E qui potrebbe essere il metodo API Sto chiamando per:

public void theirMethod() throws Exception { // This is my problem. 
    // Does stuff that could cause problems, but is 
    // lazy and implicitly throws base exception. 
    // Now it's my problem! 
} 

La mia domanda è: come faccio meglio andare a fare i conti con questa eccezione di base che viene lanciata ai miei metodi? Suppongo che sia nel mio interesse conservare in qualche modo tutte le informazioni sulle eccezioni originali mentre propagando qualcosa di più utile di un'eccezione di base. Per esempio, ho considerato la cattura e lo stoccaggio l'eccezione di base nel mio tipo di eccezione e gettando che invece:

public void myMethod() { 
    try { 
     someAPIObject.theirMethod(); // API method throwing base exception. 
    } catch (Exception e) { 
     throw new MySpecificException(e); // Re-throw my own exception. 
    } 
} 

Io non sto cercando opinioni, ma piuttosto qualche prova solida e lineare (pro) sul perché una soluzione particolare è una buona soluzione, così come qualsiasi cavaet (contro). Il mio obiettivo è su Java, ma sono curioso di eventuali concetti generali o "best practice".

+4

Sono costernato che questa domanda abbia ottenuto voti ravvicinati. È un problema molto reale nello sviluppo del software. Sebbene non ci sia una vera risposta, ci sono soluzioni oggettive con ragioni citabili. – VGR

+0

Lancio 'Exception' stesso o qualche sottoclasse sconosciuta? Se il primo, 'instanceof' non farà nulla per te. – ssube

+0

@ssube In questo caso, sì, lancia l'eccezione stessa. Ho fatto alcuni chiarimenti. – Arcensoth

risposta

2

Supponendo che si conosca un elenco completo di sottoclassi di eccezioni che possono essere generate dall'API, potrebbe essere meglio "crackare" il tipo di eccezione con un controllo di runtime e avvolgere il metodo nel proprio wrapper che genera eccezioni specifiche .

Ecco un esempio: supponiamo che l'API può lanciare tre sottoclassi specifiche di Exception - vale a dire, ExceptionOne, ExceptionTwo e ExceptionThree. Si potrebbe costruire un wrapper come questo:

class SomeApiWrapper { 
    public void myMethod() throws ExceptionOne, ExceptionTwo, ExceptionThree { 
     try { 
      someAPIObject.theirMethod(); 
     } catch (Exception e) { 
      crackException(e); 
     } 
    } 
    private static void crackException(Exception e) throws ExceptionOne, ExceptionTwo, ExceptionThree { 
     if (e instanceof ExceptionOne) throw (ExceptionOne)e; 
     if (e instanceof ExceptionTwo) throw (ExceptionTwo)e; 
     if (e instanceof ExceptionThree) throw (ExceptionThree)e; 
     throw new RuntimeException("Caught an exception of unexpected type", e); 
    } 
} 

Gli utenti del tuo API non dovranno prendere Exception (che è una cosa molto brutta) e conservare tutte le informazioni incorporate nel eccezione originale.

+0

Non conosco la sottoclasse di eccezioni, che è davvero il nocciolo del problema. Forse non ero abbastanza chiaro con il mio post originale. Terrò a mente questa tecnica, comunque, per riferimento futuro. – Arcensoth

+0

@Arcensoth Se non si conoscono le eccezioni in anticipo, ma si ha accesso al JAR compilato, è possibile scrivere un piccolo programma per trovare tutte le sottoclassi di 'Exception' definite nel programma e prenderle da lì. Vorrei anche provare a contattare gli sviluppatori della tua libreria per vedere se potevano fornire informazioni su questo problema. – dasblinkenlight

3

Questa domanda sarà senza dubbio chiusa come "troppo ampia" o "basata sull'opinione", ma mi lancerò il mio 2c prima che lo faccia.

tuo secondo esempio di codice dovrebbe (quasi) sempre essere la strada da percorrere:

public void myMethod() { 
    try { 
     someAPIObject.theirMethod(); // API method throwing base exception. 
    } catch (Exception e) { 
     throw new MySpecificException(e); // Re-throw my own exception. 
    } 
} 

La mia ragione principale di questo è che io non voglio una leaky abstraction. Ad esempio, dire che ho una sorta di repository per l'accesso agli utenti con la seguente interfaccia:

public interface UserRepository { 
    public User byId(UserId id); 
} 

E ho questo implementato da un database MySQL, in modo da avere la seguente classe concreta:

public class MySqlUserRepository implements UserRepository { 
    public User byId(UserId id); 
} 

Dentro questa classe avrò bisogno di gestire le eccezioni JDBC.Se io lascio li propagano attraverso l'interfaccia, in questo modo:

public interface UserRepository { 
    public User byId(UserId id) throws SqlException; 
} 

Poi un cliente del mio codice ora sa che sta usando JDBC in background. Se lo avvolgo, come hai fatto tu, allora l'archivio dati sottostante è completamente incapsulato, che è uno dei punti di avere un'astrazione in primo luogo. Se fornisco un'implementazione che utilizza un altro datastore, ad es. Redis, quindi SqlException non ha più significato ma avrei bisogno di aggiornare il contratto per fare in modo che i metodi generino le eccezioni che il datastore specifico potrebbe generare.

+0

La tua risposta riassume molto bene perché questa domanda è * non * basata sull'opinione pubblica. –

+0

Un buon punto per quanto riguarda le astrazioni che perdono. Sono convinto che non voglio che l'eccezione di base si propaghi dall'API oltre i miei metodi. – Arcensoth

Problemi correlati