Do Try
Camel supports the Java equivalent of try, catch, and finally directly in the DSL. It aims to work like its Java sisters but with more power.
In Camel, we prefix the keywords with do to avoid having same keyword as Java. So we have:
-
doTry -
doCatch -
doFinally -
endto end the block in Java DSL
| When using The reason is that |
EIP options
The Do Try eip supports the following options which are listed below.
| Name | Description | Default | Type |
|---|---|---|---|
note | The note for this node. | String | |
description | The description for this node. | String | |
disabled | Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime. | false | Boolean |
outputs | Required | List | |
doCatch | Catches exceptions as part of a try, catch, finally block. | List | |
doFinally | Path traversed when a try, catch, finally block exits. | FinallyDefinition |
Using doTry … doCatch … doFinally
In the route below we have all of them in action:
-
Java
-
XML
-
YAML
from("direct:start")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IOException.class, IllegalStateException.class)
.to("mock:catch")
.doFinally()
.to("mock:finally")
.end(); <route>
<from uri="direct:start"/>
<doTry>
<process ref="processorFail"/>
<to uri="mock:result"/>
<doCatch>
<exception>java.io.IOException</exception>
<exception>java.lang.IllegalStateException</exception>
<to uri="mock:catch"/>
</doCatch>
<doFinally>
<to uri="mock:finally"/>
</doFinally>
</doTry>
</route> - route:
from:
uri: direct:start
steps:
- doTry:
steps:
- process:
ref: processorFail
- to:
uri: mock:result
- doCatch:
exception:
- java.io.IOException
- java.lang.IllegalStateException
steps:
- to:
uri: mock:catch
- doFinally:
steps:
- to:
uri: mock:finally Using onWhen with doCatch
You can use Predicates with doCatch to make it determine at runtime if the block should be triggered or not. In this example, we only want to trigger if the caused exception message contains the word Damn.
-
Java
-
XML
-
YAML
from("direct:start")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IOException.class, IllegalStateException.class)
.onWhen(exceptionMessage().contains("Damn"))
.to("mock:catch")
.doCatch(CamelExchangeException.class)
.to("mock:catchCamel")
.doFinally()
.to("mock:finally")
.end(); <route>
<from uri="direct:start"/>
<doTry>
<process ref="processorFail"/>
<to uri="mock:result"/>
<doCatch>
<exception>java.io.IOException</exception>
<exception>java.lang.IllegalStateException</exception>
<onWhen>
<simple>${exception.message} contains 'Damn'</simple>
</onWhen>
<to uri="mock:catch"/>
</doCatch>
<doCatch>
<exception>org.apache.camel.CamelExchangeException</exception>
<to uri="mock:catchCamel"/>
</doCatch>
<doFinally>
<to uri="mock:finally"/>
</doFinally>
</doTry>
</route> - route:
from:
uri: direct:start
steps:
- doTry:
steps:
- process:
ref: processorFail
- to:
uri: mock:result
- doCatch:
exception:
- java.io.IOException
- java.lang.IllegalStateException
onWhen:
expression:
simple:
expression: "${exception.message} contains 'Damn'"
steps:
- to:
uri: mock:catch
- doCatch:
exception:
- org.apache.camel.CamelExchangeException
steps:
- to:
uri: mock:catchCamel
- doFinally:
steps:
- to:
uri: mock:finally Use end() to end the block
When using Java DSL you must use end() to indicate where the try … catch … finally block ends. If the route has a doFinally, then the end() should be at the end of the finally block. If there is no doFinally, then the end() should be at the end of the last doCatch.
Instead of end() you can use endDoTry() to end and return back to the try … catch scope. |
A doTry must have one or more doCatch or doFinally blocks, otherwise the route fails to start.
How doCatch matches an exception
The doCatch blocks are tried in the order they are defined, and the first doCatch that matches is used (the same as in Java). For each doCatch, the exception and its causes are matched (starting from the root cause and going upwards to the thrown exception), and the onWhen predicate (if any) must also be true.
This is different from onException (which selects the closest matching exception type across all its clauses). For example, if a doCatch(IOException.class) is defined before a doCatch(RuntimeCamelException.class), then a RuntimeCamelException caused by an IOException is caught by the doCatch(IOException.class) block.
The Exchange.EXCEPTION_CAUGHT exchange property contains the thrown exception (and not the cause that matched).
Exceptions that are not caught
An exception that is not caught by any doCatch (or an exception that is thrown in a doCatch or doFinally block) is not handled by the route error handler: onException, redelivery and the dead letter channel are not in use for the steps of a doTry … doCatch … doFinally block. The exception is thrown from the doTry, and the exchange fails.
If an exception is thrown in the doFinally block while an exception from the doTry (or doCatch) block is still not handled, then the original exception is kept and the exception from the doFinally block is added as a suppressed exception.
Stopping inside doTry
Using stop() inside the doTry or doCatch block stops routing the message, and the doFinally block is not executed.
Nested doTry … doCatch
When nesting doTry … doCatch from an outer doTry … doCatch EIP, pay extra attention when using Java DSL as the Java programming language is not indent aware so you may write code that is indented in a way where you think a catch block is associated with the other doTry, but it is not.
Given the following Java DSL:
from("direct:test")
.doTry().
doTry().
throwException(new IllegalArgumentException("Forced by me"))
.doCatch(Exception.class)
.log("docatch 1")
.throwException(new IllegalArgumentException("Second forced by me"))
.doCatch(Exception.class)
.log("docatch 2")
.end(); Both docatch 1 and docatch 2 are in the inner doTry, and the outer doTry has no catch blocks (and the route fails to start, as a doTry must have one or more doCatch or doFinally blocks). Use endDoTry() to end the blocks correctly:
from("direct:test")
.doTry().
doTry().
throwException(new IllegalArgumentException("Forced by me"))
.doCatch(Exception.class)
.log("docatch 1")
.throwException(new IllegalArgumentException("Second forced by me"))
.endDoTry() // end this doCatch block
.endDoTry() // end the inner doTry
.doCatch(Exception.class)
.log("docatch 2")
.end();