I am working on some workflow and it is possible to raise many exceptions in that. I heard that we can keep all those possible exceptions in an Enum (Exception1, Exception2 ...) and use it. How can we do that using Enums in Java?
You can add the classes of exceptions with
enum EnumWithExceptions {
ENUM1(Exception1.class, Exception2.class),
ENUM2(Exception3.class);
private final Class<? extends Exception>[] exceptions;
private EnumWithExceptions(Class<? extends Exception>... exceptions) {
this.exceptions = exceptions;
}
public boolean matches(Exception e) {
for(Class<? extends Exception> e2: exceptions)
if (e2.isInstance(e)) return true;
return false;
}
}
} catch(Exception e){
if (ENUM1.matches(e)){
//do something
} else if(ENUM2.matches(e)) {
//do something
} else {
//do something
}
}
enum Fred {
SAM(AnException.class),
I(AnotherException.class),
AM(YetAnotherException.class)
;
private Throwable t;
Fred(Throwable throwable) {
this.t = throwable;
}
public Throwable getThrowable() {
return t;
}
}
...
throw Fred.SAM.getThrowable();
Why not store the exceptions in an ArrayList? Or if you want to name the index, you could use a HashMap.
import java.util.ArrayList;
import java.util.HashMap;
public final class ExceptionStorage {
private static int exceptionCount = 0;
private static HashMap<String, Exception> indexedExceptions = new HashMap<>();
private static ArrayList<Exception> exceptions = new ArrayList();
public static void addException(Exception e) {
exceptions.add(e);
}
public static void putException(Exception e) {
indexedExceptions.put("Exception" + (++exceptionCount), e);
}
public static ArrayList<Exception> getUnindexedExceptions() {
return this.exceptions;
}
public static HashMap<String, Exception> getIndexedExceptions() {
return this.indexedExceptions;
}
}
Obviously you would have to modify the code to use either ArrayList or HashMap, but I think this would be a better solution than using Enums.
Related
I'm implementing a strategy pattern for exceptions handling
public class GlobalExceptionHandler {
private interface Strategy<T extends Exception> {
ErrorResponse extract(T e);
}
private static class ResponseStatusStrategy implements Strategy<ResponseStatusException> {
#Override
public ErrorResponse extract(ResponseStatusException e) {
return ErrorResponse.builder()
.status(e.getStatus())
.message(e.getReason())
.description(e.getReason())
.build();
}
}
private static class IllegalStateStrategy implements Strategy<IllegalStateException> {
#Override
public ErrorResponse extract(IllegalStateException e) {
return ErrorResponse.builder()
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.message(e.getMessage())
.description("")
.build();
}
}
....
I call this API like this:
Exception ex = ....; // function param
if (ex instanceof ResponseStatusException) {
errorResponse = new ResponseStatusStrategy().extract((ResponseStatusException) ex);
} else if (ex instanceof IllegalStateException) {
errorResponse = new IllegalStateStrategy().extract((IllegalStateException) ex);
} else {
errorResponse = new EmptyStrategy().extract(ex);
}
Is there a more efficient and beautiful way to implement this? Idea gets me hint that I even didn't use interface method: "method extract(T e) is never used".
It would be great to have API like this:
Strategy<???> strategy;
if (ex instanceof ResponseStatusException) {
strategy = new ResponseStatusStrategy();
} else if (ex instanceof IllegalStateException) {
strategy = new IllegalStateStrategy();
} else {
strategy = new EmptyStrategy();
}
errorResponse = strategy.extract(ex);
You are trying to solve an object creational problem. You want a particular Strategy class object based on the StatusException class. Create a new class with a factory pattern to return you the correct object. Here is some dummy code inspired from your code.
private interface Factory {
Strategy buildStrategy(Exception e);
}
private static class FactoryImpl implements Factory {
public Strategy buildStrategy(Exception e) {
if (e instanceof IOException) {
return new Strategy1();
} else {
return new EmptyStrategy();
}
}
}
private interface Strategy<T extends Exception> {
String extract();
}
private static class Strategy1 implements Strategy<IOException> {
#Override public String extract() {
return "Strategy1";
}
}
private static class EmptyStrategy implements Strategy<NamingException> {
#Override public String extract() {
return "EmptyStrategy";
}
}
public static void main(String[] args) {
var f = new FactoryImpl();
System.out.println(f.buildStrategy(new IOException()).extract());
System.out.println(f.buildStrategy(new NamingException()).extract());
}
I would like to generalize the following pattern:
setChangeListener = c -> {
try {
// do something dangerous
} catch (final IOException e) {
logger.error(e.getLocalizedMessage(), e);
}
};
I would like to use it like this:
errorLoggingSetChangeListener = c -> {
// do something dangerous
};
I was thinking about this:
public class ErrorLoggingSetChangeListener<T> implements SetChangeListener<T> {
private static final Logger logger = Logger.getLogger(ErrorLoggingSetChangeListener.class);
private final SetChangeListener<T> delegate;
#Override
public void onChanged(final SetChangeListener.Change<? extends T> change) {
try {
delegate.onChanged(change);
} catch (final Exception e) {
if (logger.isEnabledFor(Level.ERROR)) {
logger.error(e.getLocalizedMessage(), e);
}
}
}
public ErrorLoggingSetChangeListener(final SetChangeListener<T> delegate) {
super();
this.delegate = delegate;
}
}
But that is not possible, since ErrorLoggingSetChangeListener is not a Functional interface.
Any chance to convert this class to an Functional Interface?
This does not compile:
public interface ErrorLoggingSetChangeListener<T> extends SetChangeListener<T> {
static final Logger logger = Logger.getLogger(ErrorLoggingSetChangeListener.class);
#Override
default void onChanged(final SetChangeListener.Change<? extends T> change) {
try {
SetChangeListener.super.onChanged(change);
} catch (final Exception e) {
if (logger.isEnabledFor(Level.ERROR)) {
logger.error(e.getLocalizedMessage(), e);
}
}
}
}
This does also not compile:
errorLoggingSetChangeListener = new ErrorLoggingSetChangeListener<>(c -> {
throw new IOException();
});
The error message is
Unhandled exception [..]
.
This is similar to #JonnyAW's solution, but combines both classes into a single interface:
import javafx.collections.SetChangeListener;
#FunctionalInterface
public interface ErrorLoggingSetChangeListener<E> extends SetChangeListener<E> {
public void delegate(Change<? extends E> change) throws Exception ;
#Override
public default void onChanged(Change<? extends E> change) {
try {
delegate(change);
} catch (Exception exc) {
// just do a System.out.println here to demo we reach this block:
System.out.println("Custom error handling...");
exc.printStackTrace();
}
}
}
And here's a demo of using this:
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
public class Test {
public static void main(String[] args) {
ObservableSet<String> set = FXCollections.observableSet();
ErrorLoggingSetChangeListener<String> listener = c -> {
if (c.wasAdded()) {
int i = Integer.parseInt(c.getElementAdded());
System.out.println("Value added: "+i);
}
};
set.addListener(listener);
set.add("42");
set.add("What do you get when you multiply 6 by 9?");
}
}
which generates the expected output:
Value added: 42
Custom error handling...
java.lang.NumberFormatException: For input string: "What do you get when you multiply 6 by 9?"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at Test.lambda$0(Test.java:10)
at ErrorLoggingSetChangeListener.onChanged(ErrorLoggingSetChangeListener.java:12)
at com.sun.javafx.collections.SetListenerHelper$SingleChange.fireValueChangedEvent(SetListenerHelper.java:163)
at com.sun.javafx.collections.SetListenerHelper.fireValueChangedEvent(SetListenerHelper.java:72)
at com.sun.javafx.collections.ObservableSetWrapper.callObservers(ObservableSetWrapper.java:128)
at com.sun.javafx.collections.ObservableSetWrapper.add(ObservableSetWrapper.java:269)
at Test.main(Test.java:17)
here is my implementation, that will compile:
ErrorLoggingSetChangeListener:
import javafx.collections.SetChangeListener;
public class ErrorLoggingSetChangeListener<T> implements SetChangeListener<T> {
private DangerousInterface<T> delegate;
public ErrorLoggingSetChangeListener(DangerousInterface<T> delegate) {
super();
this.delegate = delegate;
}
#Override
public void onChanged(Change<? extends T> change) {
try {
this.delegate.delegate(change);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
DangerousInterface:
public interface DangerousInterface<T> {
public void delegate(Change<? extends T> change) throws Exception;
}
Main:
SetChangeListener<String> listener = new ErrorLoggingSetChangeListener<>((test) -> {
//no errors here now
throw new Exception();
});
I got definitely no compile errors
EDIT: ok, I got the Problem, you need a new Interface that can actually throw something, now you can wrap it in onChanged
I'm having trouble rethrowing exceptions thrown by stream while "accessing" it.
For example, if I have a stream which throws ExceptionA:
Stream<String> stream = Stream.of("dummy").map(d -> {throw new ExceptionA();});
try {
stream.collect(Collectors.toList());
} catch (ExceptionA e) {}
What I want to achieve is create new stream2 out of stream without consuming stream which will throw ExceptionB when it's collected
try {
stream2.collect(Collectors.toList());
} catch (ExceptionB e) {}
Obviously
Iterator<String> newIt = createRethrowingIterator(stream.iterator());
Stream<String> stream2 = StreamSupport.stream(Spliterators.spliteratorUnknownSize(newIt, Spliterator.NONNULL), false)
where createRethrowingIterator wraps original iterator and returns new one which actually rethrows ExceptionA to ExceptionB
is not what I want as stream.iterator() is terminal operator, i.e. it will consume stream, which might lead to memory problems if stream is really large
This task is better solved using Spliterator rather than Iterator. It simplifies the logic, as you only have to implement a single method, tryAdvance, by delegating the the source’s tryAdvance method.
It also opens the opportunity for performance improvements by delegating the methods characteristics() and estimateSize() to the source, as the exception translation feature does not change them. You can also get decent parallel support, by implementing trySplit via delegating to the source. You only have to wrap the result exactly like the first Spliterator:
public class Rethrowing<T,E extends Throwable> implements Spliterator<T> {
public static <E extends Throwable, T> Stream<T> translateExceptions(
Stream<T> source, Class<E> catchType,
Function<? super E, ? extends RuntimeException> translator) {
return StreamSupport.stream(new Rethrowing<>(
source.spliterator(), catchType, translator), source.isParallel());
}
private final Spliterator<T> source;
private final Class<E> catchType;
private final Function<? super E, ? extends RuntimeException> translator;
public Rethrowing(Spliterator<T> sp, Class<E> catchType,
Function<? super E, ? extends RuntimeException> translator) {
this.source = sp;
this.catchType = catchType;
this.translator = translator;
}
#Override public boolean tryAdvance(Consumer<? super T> action) {
try { return source.tryAdvance(action); }
catch(Throwable t) {
if(catchType.isInstance(t))
throw translator.apply(catchType.cast(t));
else throw t;
}
}
#Override public int characteristics() {
return source.characteristics();
}
#Override public long estimateSize() {
return source.estimateSize();
}
#Override public Spliterator<T> trySplit() {
Spliterator<T> split = source.trySplit();
return split==null? null: new Rethrowing<>(split, catchType, translator);
}
}
you can use this utility class like
class ExceptionA extends IllegalStateException {
public ExceptionA(String s) {
super(s);
}
}
class ExceptionB extends IllegalStateException {
public ExceptionB(Throwable cause) {
super(cause);
}
}
Rethrowing.translateExceptions(
Stream.of("foo", "bar", "baz", "", "extra")
.peek(s -> System.err.println("consuming \""+s+'"'))
.map(s -> { if(s.isEmpty()) throw new ExceptionA("empty"); return s; }),
ExceptionA.class, ExceptionB::new)
.forEach(s -> System.err.println("terminal operation on "+s));
to get
consuming "foo"
terminal operation on foo
consuming "bar"
terminal operation on bar
consuming "baz"
terminal operation on baz
consuming ""
Exception in thread "main" ExceptionB: ExceptionA: empty
…
Caused by: ExceptionA: empty
…
Here, ExceptionB::new is the translation function, which is equivalent to exA->new ExceptionB(exA).
Why don't you wrap that call which throws your ExceptionA into a mapping function which if thrown transforms it into ExceptionB immediately, like:
try {
List<T> l = stream.map(o -> wrapped(() -> o.whateverThrowsExceptionA())).collect(toList());
// or do your stream2 operations first, before collecting the list
} catch (ExceptionB b) {
// handle your exception
}
where wrapped in that case would be similar to:
<T> T wrapped(Callable<T> o) throws ExceptionB {
try {
return callable.call();
} catch (Exception e) {
throw new ExceptionB(e);
}
}
You may even want to adjust the wrapper to take in a custom ExceptionA-catching function.
Alright, I failed to understand that terminal operation does not mean that stream is fully consumed. Thank you Louis Wasserman for clarifying this.
To demonstrate it I wrote some unit tests:
import org.junit.Test;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* #author Beka Tsotsoria
*/
public class StreamExceptionRethrowingTest {
#Test
public void throwingIteratorMustBeConsumedWhenStreamIsCollected() throws Exception {
ThrowingIterator itToBeConsumed = new ThrowingIterator();
assertThatThrownBy(() -> streamFromIterator(itToBeConsumed)
.collect(Collectors.toList()))
.isInstanceOf(ExceptionA.class);
assertThat(itToBeConsumed.consumed()).isTrue();
}
#Test
public void throwingIteratorMustNotBeConsumedUntilNewStreamIsCollected() throws Exception {
ThrowingIterator itNotToBeConsumed = new ThrowingIterator();
RethrowingIterator rethrowingIterator = new RethrowingIterator(streamFromIterator(itNotToBeConsumed).iterator());
assertThat(itNotToBeConsumed.consumed()).isFalse();
Stream<String> stream2 = streamFromIterator(rethrowingIterator);
assertThat(itNotToBeConsumed.consumed()).isFalse();
assertThatThrownBy(() -> stream2
.collect(Collectors.toList()))
.hasCauseInstanceOf(ExceptionA.class)
.isInstanceOf(ExceptionB.class);
assertThat(itNotToBeConsumed.consumed()).isTrue();
}
#Test
public void streamIteratorMustNotBeConsumedUntilNewStreamIsCollected() throws Exception {
Stream<String> stream = Stream.of("dummy")
.map(d -> {
throw new ExceptionA();
});
Stream<String> stream2 = streamFromIterator(new RethrowingIterator(stream.iterator()));
// No exceptions so far, i.e. stream.iterator() was not consumed
assertThatThrownBy(() -> stream2
.collect(Collectors.toList()))
.hasCauseInstanceOf(ExceptionA.class)
.isInstanceOf(ExceptionB.class);
}
private Stream<String> streamFromIterator(Iterator<String> it) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.NONNULL), false);
}
static class ThrowingIterator implements Iterator<String> {
private boolean hasNextCalled;
private boolean nextCalled;
#Override
public boolean hasNext() {
hasNextCalled = true;
throw new ExceptionA();
}
#Override
public String next() {
nextCalled = true;
throw new ExceptionA();
}
public boolean consumed() {
return hasNextCalled || nextCalled;
}
}
static class RethrowingIterator implements Iterator<String> {
private Iterator<String> it;
public RethrowingIterator(Iterator<String> it) {
this.it = it;
}
#Override
public boolean hasNext() {
try {
return it.hasNext();
} catch (ExceptionA e) {
throw new ExceptionB(e);
}
}
#Override
public String next() {
try {
return it.next();
} catch (ExceptionA e) {
throw new ExceptionB(e);
}
}
}
static class ExceptionA extends RuntimeException {
}
static class ExceptionB extends RuntimeException {
public ExceptionB(Throwable cause) {
super(cause);
}
}
}
Thanks for your comments. Cheers!
I have defined my own expection class:
public class ProduktException extends Exception {
public ProduktException(String msg){
//null
}
public static void throwProduktNotCreatedException() throws ProduktException {
throw new ProduktException("Cannot be created!");
}
public static void throwProduktNotDeletedException () throws ProduktException {
throw new ProduktException("Cannot be deleted!");
}
}
My Problem is I do not know how to throw them when I try:
try {
...
} catch(ProduktNotDeletedException e) {
e.toString();
}
That does not work... But I want to have these structure! What is wrong?
I appreaciate your answer!!!
UPDATE:
My Problem is, I do not want to create several Exception Klasses I want to have all Exceptions in one class. Is there possibly a solution for that?
If you need to differentiate between different kinds of exceptions, just create 2 different exceptions, maybe something like:
public class ProduktException extends Exception
{
public ProduktException(String msg){
//null
}
}
Then have:
public class ProduktNotDeletedException extends ProduktException
{
....
}
and
public class ProduktNotCreatedException extends ProduktException
{
....
}
Then you can catch one or the other, or both.
try {
...
} catch(ProduktNotDeletedException e1) {
e1.toString();
} catch(ProduktNotCreatedException e2) {
e2.toString();
}
EDIT:
For a single class what I mean is:
public class ProduktException extends Exception {
boolean notDeleted;
boolean notCreated;
public ProduktException(String msg){
super(msg);
}
public boolean isNotDeleted() {
return(notDeleted);
}
public boolean isNotCreated() {
return(notCreated);
}
public static void throwProduktNotCreatedException() throws ProduktException {
ProduktException e = new ProduktException("Cannot be created!");
e.notCreated = true;
throw e;
}
public static void throwProduktNotDeletedException () throws ProduktException {
ProduktException e = new ProduktException("Cannot be deleted!");
e.notDeleted = true;
throw e;
}
}
Then in your try/catch:
try {
...
} catch(ProduktException e) {
e.toString();
if(e.isNotCreated()) {
// do something
}
if(e.isNotDeleted()) {
// do something
}
}
You need to either catch ProduktException, e.g.
try {
...
} catch (ProduktException e) {
e.toString();
}
or declare subtypes, e.g.
public ProduktNotDeletedException extends ProduktException
You'll probably want to pass the message in the constructor up, so add the following in your constructor:
super(msg);
The Syntax given below.
class RangeException extends Exception
{
String msg;
RangeException()
{
msg = new String("Enter a number between 10 and 100");
}
}
public class MyCustomException
{
public static void main (String args [])
{
try
{
int x = 1;
if (x < 10 || x >100) throw new RangeException();
}
catch(RangeException e)
{
System.out.println (e);
}
}
}
What you could do if you don't want to create multiple subclasses of your ProduktException for each different type of exception you need to throw is to include a code in the exception which will let you know what is wrong. Something like this:
public class ProduktException extends Exception {
private Code exceptionCode;
private String message
public ProduktException(Code code, String msg){
this.message = msg;
this.exceptionCode = code;
}
//Getters and setters for exceptionCode and message
}
Code can be an enum so that your application can know that each code corresponds to a specific "problem" (product not created, product not deleted, etc.). You can then throw your exceptions like this
throw new ProduktException(Code.PRODUCT_NOT_CREATED,
"Error while creating product");
And when you catch it you can differentiate based on the code.
catch (ProduktException ex) {
if (ex.getExceptionCode().equals(Code.PRODUCT_NOT_CREATED)) {
...
}
else {
...
}
}
I cooked up a class ExceptionHandler<T extends Exception, OptionalReturnType> (see below) to eliminate some (what I view as) boilerplate code which was cluttering up actual implementation, while still providing a hook for explicit Exception handling if desired in the future. For the most part, in my application (essential a scientific computation), there is no such thing as recovery from exceptions - I need a log of the problem so I can fix it, but otherwise I'm just going to re-run once the problem is corrected.
Do other people do this (at least, in my specific application situation)? Is it dumb to do so (if yes, some explanation as to why would be nice)?
ExceptionHandler:
public abstract class ExceptionHandler<ExceptionType extends Exception,OptionalReturn> {
public abstract OptionalReturn handle(ExceptionType e);
//assorted boilerplate ExceptionHandling, e.g.:
public static <ET extends Exception> ExceptionHandler<ET, ?> swallower(final boolean printStackTrace, final String string) {
return new ExceptionHandler<ET,Object>() {
#Override public Object handle(ET e) {
if(printStackTrace) { e.printStackTrace(); }
if(string!=null && !string.isEmpty()) { System.err.println(string); }
return null;
}
};
}
public static <ET extends Exception> ExceptionHandler<ET, ?> swallower() { return swallower(false,null); }
}
example use (which I'm in the process of chopping down so I'm actually not writing quite so much):
public class Getter<From> implements Function<Future<? extends From>, From> {
private ExceptionHandler<InterruptedException,?> IEH;
private ExceptionHandler<ExecutionException,?> EEH;
public static final ExceptionHandler<InterruptedException,?> IEH_SWALLOWER = ExceptionHandler.swallower(true,"Returning null.");
public static final ExceptionHandler<ExecutionException,?> EEH_SWALLOWER = ExceptionHandler.swallower(true,"Returning null.");
private Getter() { this(IEH_SWALLOWER,EEH_SWALLOWER); }
private Getter(ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
this.IEH = IEH;
this.EEH = EEH;
}
public static <T> Getter<T> make() { return new Getter<T>(); }
public static <T> Getter<T> make(ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
return new Getter<T>(IEH, EEH);
}
#Override public From apply(Future<? extends From> from) {
if (from==null) throw new NullPointerException("Null argument in call with Getter.");
return getter(from, IEH, EEH);
}
private static <T> T getter(Future<T> src, ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
try { return src.get(); }
catch (InterruptedException e) { IEH.handle(e); }
catch (ExecutionException e) { EEH.handle(e); }
return null;
}
}
which is used with the Guava libraries to do some embarrassingly-parallel calculations, and makes the actual Iterable transformation of Futures into something like Iterables.transform(futureCollection,Getter.make()) instead of tangle of inner-classes and exception handling.
I find the code honestly hard to follow and understand. It's full of static which is usually a bad sign in OO design and it's hard to follow with the generics.
Wouldn't something simpler like this work as well?
private static <T> T getter(Future<T> src) {
try { return src.get(); }
catch (InterruptedException e) { handle( "some text"); }
catch (ExecutionException e) { handle( e ) }
return null;
}
You can implement as many handle method as necessary in a base class (or in a static utility class) and use them in the catch block as necessary. Methods will be selected based on the signature, so if you want to print the text, you pass the string, if you want the stack trace you pass the exception (or both). Which leads to the combinations:
handle( String msg )
handle( Exception e )
handle( Exception e, String msg )
This solution has less if, which is usually a good sign as well.
But I have maybe missed a point, given that the code you published is just an excerpt of the whole code.
Have a look otherwise at this question, which is also related: Pluggable Error Handling Strategy
EDIT
If the solution I proposed above is too simple for your need, here are two other ways:
public class AbstractGetter<From> implements Function<Future<? extends From>, From> {
private abstract handleInterrupt( Exception e );
private abstract handleExecution( Exception e );
private static <T> T getter(Future<T> src ) {
try { return src.get(); }
catch (InterruptedException e) { handleInterrupt(e) }
catch (ExecutionException e) { handleExecution(e) }
return null;
}
}
And you implement the X concrete class that correspond the various exception handling strategies. That's essentially the template pattern.
You can still use delegation, but at a more coarse-grained level. Instead of providing individual handler, you provide a handler strategy. That's kind of variation of the strategy pattern then.
public interface ErrorStrategy
{
public void handleInterrupt(Exception e);
public void handleExecution(Exception e);
}
public class Getter<From> implements Function<Future<? extends From>, From> {
ErrorStrategy handler = new DefaultErrorStrategy(). // default one
public Getter<From>()
{
}
public Getter<From>( ErrorStrategy h )
{
this.handler = h.
}
private static <T> T getter(Future<T> src ) {
try { return src.get(); }
catch (InterruptedException e) { handler.handleInterrupt(e) }
catch (ExecutionException e) { handler.handleExecution(e) }
return null;
}
}
You can create the X error handling strategies that you need.
I think it's a good solution, but it could benefit from an ExceptionHandlerFactory and some xml files.