Camel end vs endChoice - not the usual query

SHORT ANSWER: I will call myself on this so no one else has to, the answer is that you are doing it wrong and should not have nested choices.

LONG ANSWER: I inherited a complicated route builder and was trying to clean it up to make it clearer. But straightening and putting in either end() or endChoice() just broke things. And, yes, the above fix still broke things. I did not understand how Camel knew which block to go to. Research and trying to find good examples of nesting eventually drove home the fact that Camel is not really designed for nesting choices. It allows it, but due to limitations in Java, it does not do it well. So I tried removing my nested choices. While this would have been possible, it would have meant ugly redundant conditionals, like:

choice()
  .when(x and a)
    //do stuff xa
  .when(x not a)
    // do other x stuff
  .when(y and a)
    // do y stuff

Only mine would have had at least another level. Further thought and recalling things that I had read brought about the second bit of enlightenment. The whole point of Camel is directing routes. Each choice's when block should just be pointing the process to a route. It should not be thinking, processing, or anything. In the end, our group is going to be refactoring to remove most of the logic from the route builder to a bean. The design we will be working towards will be something simple:

   from(uri)
     .bean(class, method)  // do any processing
     .choice()
       .when(header("result").isEqualTo("A")
          .to(routeA)
       .endChoice()
       .when(header("result").isEqualTo("B")
          .to(routeB)
       .endChoice()
       .when(header("result").isEqualTo("C")
          .to(route)
       .endChoice()
      .end()

My advice to you is to avoid nesting choices. Particularly complicated ones. You might get it to work, but you will not be able to trust it when you have to make changes later. If you find yourself tempted to use nested choices, examine what you are trying to accomplish and decide if it really belongs in a route builder.


Coming late in the game, but might help.

Nested choice definitions work just fine with Camel. Only your terminators are wrong:

  • .endChoice() --> to close a "when" predicate
  • .end() --> to close the entire "choice" block

I know, the syntax is a bit confusing.

So in your case:

.choice()
    .when(X1)
        // do stuff

        .choice()
            .when(Y)
                //do more stuff
            .endChoice() // close Y condition

        .end() // close inner choice block

    .endChoice() // close X1 condition

    .when(X2)
        // do other stuff
    .endChoice() // close X2 condition

    .otherwise()
        // default case
    .endChoice() // close default condition

.end()

In practice, you don't have to close all when predicates, only for multiple child routings. In my humble opinion, being super meticulous with the indentation helps a lot.