Java Exception Handling

From MPDLMediaWiki
Jump to navigation Jump to search

Problem description[edit]

Modules need dependencies of other modules only because of their exception classes[edit]

From validation/ItemValidating:

   String validateItemXml(final String itemXml) throws
           ValidationSchemaNotFoundException,
           TechnicalException;

From importmanager/ImportHandler:

   byte[] doFetch(String sourceName, String identifier) throws FileNotFoundException, 
           IdentifierNotRecognisedException, 
           SourceNotAvailableException, 
           TechnicalException,
           FormatNotRecognizedException;

Stacktraces are sometimes swallowed[edit]

   try 
   {
       ...					
   } 
   catch (MalformedURLException e) 
   {LOGGER.error("Error when replacing regex in fetching URL"); e.printStackTrace(); }
   catch(UnsupportedEncodingException e)
   {e.printStackTrace();}

   try 
   {
       ...					
   } 
   catch (JiBXException e) 
   {
       e.getCause();
   }

Sometimes, excessive stacktraces are shown, even without useful information[edit]

Example from coreservices: File:Exception1.txt

Logger.error, System.out and e.printStackTrace are mixed up happily[edit]

see above

No distinction between exceptions and errors/checked and unchecked exceptions[edit]

Compare Exception and Error

Different interface boundaries handle exceptions differently[edit]

  • Java --> Java exception handling
  • EJB --> partly controlled Java exception handling (RemoteException, EJBException)
  • SOAP --> eventually generating exception classes
  • REST --> error communication via status codes

Conclusion[edit]

Distinguish between repairable exceptions and errors[edit]

Decide whether your module is able to fix the exception (take default values, look somewhere else, try again, ...) or not.

Only catch repairable exceptions[edit]

  • If an exception is somehow repairable, try this in the catch-block
  • If the repairing is critical in some respect, at least log a warning message (e.g. logger.warn("Value for xyz not found, taking default value"))
  • If repairing fails treat the exception as an error

Inside a module, prefer unchecked exceptions[edit]

Turn checked exceptions from third-party modules into unchecked exceptions, e.g.

   private void myMethod()
       try
       {
           connection.executeStatement(sql);
       }
       catch (SQLException sqle)
       {
           throw new RuntimeException("Error executing statement '" + sql + "'", sqle);
       }
   }

Inside a module, always throw errors up as they are (alternatively)[edit]

Do not care for exceptions at all, just declare them to be thrown, e.g.

   private void myMethod() throws SQLException
       connection.executeStatement(sql);
   }

When catching exceptions, log appropriately[edit]

  • use log4j, not System.out
  • use the two-argument methods:
    • logger.error("Error geting server.name property", ex);
    • logger.error("Error geting server.name property"); --> Exception information is lost
    • logger.error(ex); --> Only ex.toString() is logged, other exception information is lost
  • when an exception is rethrown, do not log (except when throwing out of the module)

Throw self-defined exceptions that are defined inside the throwing module[edit]

  • For exceptions concerning the logic of the module, exceptions should be defined and checked
  • No third module should be necessary to define these exceptions

Between modules, throw only generic exceptions[edit]

e.g. IllegalArgumentException, IllegalStateException, RuntimeException

Open questions[edit]

  • Shall interfaces define checked exceptions?
    • If so, shall self-defined exceptions be used?

Links[edit]