Code Monkey home page Code Monkey logo

java-error-handler's Introduction

ErrorHandler

Download Bintray Travis

Error handling library for Android and Java

Download

Download the latest JAR or grab via Maven:

<dependency>
  <groupId>com.workable</groupId>
  <artifactId>error-handler</artifactId>
  <version>0.9.1</version>
  <type>pom</type>
</dependency>

or Gradle:

compile 'com.workable:error-handler:0.9.1'

Usage

Let's say we're building a messaging Android app that uses both the network and a local database.

We need to:

Setup a default ErrorHandler once

  • Configure the default ErrorHandler
  • Alias errors to codes that are easier to use like Integer, String and Enum values
  • Map errors to actions to take when those errors occur (exceptions thrown)
// somewhere inside MessagingApp.java

ErrorHandler
  .defaultErrorHandler()

  // Bind certain exceptions to "offline"
  .bindErrorCode("offline", errorCode -> throwable -> {
      return throwable instanceof UnknownHostException || throwable instanceof ConnectException;
  })

  // Bind HTTP 404 status to 404
  .bindErrorCode(404, errorCode -> throwable -> {
      return ((HttpException) throwable).code() == 404;
  })

  // Bind HTTP 500 status to 500
  .bindErrorCode(500, errorCode -> throwable -> {
      return ((HttpException) throwable).code() == 500;
  })

  // Bind all DB errors to a custom enumeration
  .bindErrorCodeClass(DBError.class, errorCode -> throwable -> {
      return DBError.from(throwable) == errorCode;
  })

  // Handle HTTP 500 errors
  .on(500, (throwable, errorHandler) -> {
    displayAlert("Kaboom!");
  })

  // Handle HTTP 404 errors
  .on(404, (throwable, errorHandler) -> {
    displayAlert("Not found!");
  })

  // Handle "offline" errors
  .on("offline", (throwable, errorHandler) -> {
    displayAlert("Network dead!");
  })

  // Handle unknown errors
  .otherwise((throwable, errorHandler) -> {
    displayAlert("Oooops?!");
  })

  // Always log to a crash/error reporting service
  .always((throwable, errorHandler) -> {
    Logger.log(throwable);
  });

Use ErrorHandler inside catch blocks

// ErrorHandler instances created using ErrorHandler#create(), delegate to the default ErrorHandler
// So it's actually a "handle the error using only defaults"
// i.e. somewhere inside MessageListActivity.java
try {
  fetchNewMessages();
} catch (Exception ex) {
  ErrorHandler.create().handle(ex);
}

Override defaults when needed

// Configure a new ErrorHandler instance that delegates to the default one, for a specific method call
// i.e. somewhere inside MessageListActivity.java
try {
  fetchNewMessages();
} catch (Exception ex) {
  ErrorHandler
    .create()
    .on(StaleDataException.class, (throwable, errorHandler) -> {
        reloadList();
        errorHandler.skipDefaults();
    })
    .on(404, (throwable, errorHandler) -> {
        // We handle 404 specifically on this screen by overriding the default action
        displayAlert("Could not load new messages");
        errorHandler.skipDefaults();
    })
    .on(DBError.READ_ONLY, (throwable, errorHandler) -> {
        // We could not open our database to write the new messages
        ScheduledJob.saveMessages(someMessages).execute();
        // We also don't want to log this error because ...
        errorHandler.skipAlways();
    })
    .handle(ex);
}

Things to know

ErrorHandler is thread-safe.

API

Initialize

  • defaultErrorHandler() Get the default ErrorHandler.

  • create() Create a new ErrorHandler that is linked to the default one.

  • createIsolated() Create a new empty ErrorHandler that is not linked to the default one.

Configure

  • on(Matcher, Action) Register an Action to be executed if Matcher matches the error.

  • on(Class<? extends Exception>, Action) Register an Action to be executed if error is an instance of Exception.

  • on(T, Action) Register an Action to be executed if error is bound to T, through bindErrorCode() or bindErrorCodeClass().

  • otherwise(Action) Register an Action to be executed only if no other Action gets executed.

  • always(Action) Register an Action to be executed always and after all other actions. Works like a finally clause.

  • skipFollowing() Skip the execution of any subsequent Actions except those registered via always().

  • skipAlways() Skip all Actions registered via always().

  • skipDefaults() Skip any default actions. Meaning any actions registered on the defaultErrorHandler instance.

  • bindErrorCode(T, MatcherFactory<T>) Bind instances of T to match errors through a matcher provided by MatcherFactory.

  • bindErrorCodeClass(Class<T>, MatcherFactory<T>) Bind class T to match errors through a matcher provided by MatcherFactory.

  • clear() Clear all registered Actions.

Execute

  • handle(Throwable) Handle the given error.

About

A common problem in software, specially in UI software is that of error handling.

One way to classify errors can be by how they relate to the problem domain. Some errors, like network or database errors are orthogonal to the problem domain and designate truly exceptional conditions, while others are core parts of the domain like validation and authentication errors.

Another way to classify errors is by their scope. Are they common throughout the application or specific to a single screen, object or even method? Think of UnauthorizedException versus InvalidPasswordException.

And let's not forget another very simple distinction between errors. Those that are known at authoring time and thus expected (despite of how probable is that they occur), and those that are unknown until runtime.

With that in mind, we usually want to:

  1. have a default handler for every expected (exceptional, common or not) error
  2. handle specific errors as appropriate based on where and when they occur
  3. have a default catch-all handler for unknown errors
  4. override any default handler if needed
  5. keep our code DRY

Java, as a language, provides you with a way to do the above. By mapping exceptional or very common errors to runtime exceptions and catching them lower in the call stack, while having specific expected errors mapped to checked exceptions and handle them near where the error occurred. Still, countless are the projects where this simple strategy has gone astray with lots of errors being either swallowed or left for the catch-all Thread.UncaughtExceptionHandler. Moreover, it usually comes with significant boilerplate code. ErrorHandler however eases this practice through its fluent API, error aliases and defaults mechanism.

This library doesn't try to solve Java specific problems, although it does help with the log and shallow anti-pattern as it provides an opinionated and straightforward way to act inside every catch block. It was created for the needs of an Android app and proved itself useful very quickly. So it may work for you as well. If you like the concept and you're developing in Swift or Javascript, we're baking 'em and will be available really soon.

License

The MIT License

Copyright (c) 2013-2016 Workable SA

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

java-error-handler's People

Contributors

pavlospt avatar th3hunt avatar charbgr avatar

Watchers

Michael jentsch avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.