Java – Design strategy for wrapping exceptions

exception handlingexceptionsinterfacesjava

I'm implementing a type of Repository for a framework/library that has (roughly) the following:

public interface FooRepository {

    boolean contains(String id);

    Foo fetch(String id);

    void commit(Foo foo):
}

We can implement it several different ways, depending on what storage medium we're using; for example

public class FileFooRepositiory implements FooRepository {

    public boolean contains(String id) {
        return fileExistsInFileSystem(id);
    }

    public Foo fetch(final String id) {
        return parseFooFromFile(id);
    }

    public void commit(final Foo foo) {
        writeFooToFile(foo);
    }
}

But we can also have

public class SQLFooRepositiory implements FooRepository {

    public SQLFooRepository(Connection connection) {
        // ...
    }

    public boolean contains(String id) {
        return fooExistsInDatabase(id);
    }

    public Foo fetch(final String id) {
        return parseFooFromDatabase(id);
    }

    public void commit(final Foo foo) {
        writeFooToDatabase(foo);
    }
}

There can also be implementations that store Foo objects in a Map<String, Foo> or ones that use external storage systems (appfabric, redis, etc).

However, there are things that can prevent each of these implementation from doing what they are supposed to do. They would each throw a different type of Exception. For SQLException, most things that could happen would use this one exception. For the file-based, it would be some sort of IOException, more specifically, FileNotFoundException, AccessDeniedException, etc.

My question is this: How can I change the contract of the FooRepository interface to allow these types of Exceptions being thrown, without using the throws Exception clause. My initial thought was to have a RepositoryException that would extend RuntimeException and wrap the actual exceptions

try {
    // ...
}
catch (SQLException sqle) {
    throw new RepositoryException(sqle);
}

but I'm not sure if this is the proper strategy I should be using.

Best Answer

Your solution is correct: repository should throw a generic RepositoryException-type to signal that something went wrong. You wrap the actual exception in that RepositoryException so your logging can get access to the data it needs and your consumers can trap the generic exception and handle it somewhere down the line. Wrapping the actual exceptions hides the implementation details of the concrete repository from the consumer.

The only reason you would differentiate between the exceptions (eg return specific exceptions from the interface) is when the handling of one exception type should be different from the other. In this case I can't really think of a reason you would handle exceptions from the repository differently, so just use the RepositoryException.

Related Topic