Exception Clause
You can use the Exception Clause in the Java DSL to
specify the error handling you require on a per exception type basis
using the onException() method. To get started we give quick sample
before digging into how it works.
For example if you want to perform a specific piece of processing if a certain exception is raised you can do this simply via:
-
Java
-
XML
-
YAML
onException(ValidationException.class)
.to("activemq:validationFailed");
from("seda:inputA")
.to("validation:foo/bar.xsd", "activemq:someQueue");
from("seda:inputB")
.to("direct:foo")
.to("rnc:mySchema.rnc", "activemq:anotherQueue");
<onException>
<exception>org.apache.camel.ValidationException</exception>
<to uri="activemq:validationFailed"/>
</onException>
<route>
<from uri="seda:inputA"/>
<to uri="validation:foo/bar.xsd"/>
<to uri="activemq:someQueue"/>
</route>
<route>
<from uri="seda:inputB"/>
<to uri="direct:foo"/>
<to uri="rnc:mySchema.rnc"/>
<to uri="activemq:anotherQueue"/>
</route>
- onException:
exception:
- org.apache.camel.ValidationException
steps:
- to:
uri: activemq:validationFailed
- route:
from:
uri: seda:inputA
steps:
- to:
uri: validation:foo/bar.xsd
- to:
uri: activemq:someQueue
- route:
from:
uri: seda:inputB
steps:
- to:
uri: direct:foo
- to:
uri: rnc:mySchema.rnc
- to:
uri: activemq:anotherQueue
Here if the processing of seda:inputA or seda:inputB cause
a ValidationException to be thrown (such as due to the XSD
validation of the Validation component),
then the message will be sent to the
activemq:validationFailed queue.
You can define multiple onException clauses for different behavior:
-
Java
-
XML
-
YAML
onException(ValidationException.class)
.to("activemq:validationFailed");
onException(com.foo.ShipOrderException.class)
.to("activemq:shipFailed");
from("seda:order")
.to("bean:processOrder");
<onException>
<exception>org.apache.camel.ValidationException</exception>
<to uri="activemq:validationFailed"/>
</onException>
<onException>
<exception>com.foo.ShipOrderException</exception>
<to uri="activemq:shipFailed"/>
</onException>
<route>
<from uri="seda:order"/>
<to uri="bean:processOrder"/>
</route>
- onException:
exception:
- org.apache.camel.ValidationException
steps:
- to:
uri: activemq:validationFailed
- onException:
exception:
- com.foo.ShipOrderException
steps:
- to:
uri: activemq:shipFailed
- route:
from:
uri: seda:order
steps:
- to:
uri: bean:processOrder
Scopes
Exception clauses is scoped as either:
-
global (for Java DSL that is per
RouteBuilderinstances, to reuse, see note below) -
or route specific
Where the global are the simplest and most easy to understand. In the advanced section we dig into the route specific and even combining them. However
Global scope for Java DSL is per RouteBuilder instance, so if you
want to share among multiple RouteBuilder classes, then create a
base abstract RouteBuilder class and put the error handling logic in
its configure method. And then extend this class, and make sure to
class super.configure(). We are just using the Java inheritance
technique.
How Does Camel Select Which Clause Should Handle a Given Thrown Exception?
Camel uses DefaultExceptionPolicyStrategy to determine a strategy
how an exception being thrown should be handled by which onException
clause. The strategy is:
-
the order in which the
onExceptionis configured takes precedence. Camel will test from first…last defined. -
Camel will start from the bottom (nested caused by) and recursive up in the exception hierarchy to find the first matching
onExceptionclause. -
instanceoftest is used for testing the given exception with theonExceptionclause defined exception list. An exactinstanceofmatch will always be used, otherwise theonExceptionclause that has an exception that is the closets super of the thrown exception is selected (recurring up the exception hierarchy).
This is best illustrated with an exception:
onException(IOException.class)
.maximumRedeliveries(3);
onException(OrderFailedException.class)
.maximumRedeliveries(2);
In the sample above we have defined two exceptions in
which IOException is first, so Camel will pickup this exception if
there is a match. IOException that is more general is selected then.
So if an exception is thrown with this hierarchy:
+ RuntimeCamelException (wrapper exception by Camel)
+ OrderFailedException
+ IOException
+ FileNotFoundException
Then Camel will try testing the exception in this order:
FileNotFoundException, IOException, OrderFailedException and
RuntimeCamelException.
As we have defined a onException(IOException.class) Camel will
select this as it’s the closest match.
If we add a third onException clause with the
FileNotFoundException
onException(IOException.class)
.maximumRedeliveries(3);
onException(OrderFailedException.class)
.maximumRedeliveries(2);
onException(FileNotFoundException.class)
.handled(true)
.to("log:nofile");
Then with the previous example Camel will now use the last
onException(FileNotFoundException.class) as its an exact match.
Since this is an exact match it will override the
general IOException that was used before to handle the same
exception thrown.
Now a new situation if this exception was thrown instead:
+ RuntimeCamelException (wrapper exception by Camel)
+ OrderFailedException
+ OrderNotFoundException
Then the onException(OrderFailedException.class) will be selected -
no surprise here.
And this last sample demonstrates the instanceof test aspect in
which Camel will select an exception if it’s an instance of the defined
exception in the onException clause. Illustrated as:
+ RuntimeCamelException (wrapper exception by Camel)
+ SocketException
Since SocketException is an instanceof IOException, Camel will
select the onException(IOException.class) clause.
More Information
For detailed documentation on specific topics, see the following sub-pages:
-
Redelivery — Configuring redelivery policy, async delayed redelivery, catching multiple exceptions
-
Handling Patterns — Handled vs continued, using original message, custom failure handlers
-
Advanced Usage — Global vs route-specific, onWhen predicate, onRedelivery processor, custom strategies