0
import static java.lang.System.out;

import org.apache.camel.ExchangePattern;
import org.apache.camel.Message;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

class RequestReplyMessageSample {

    class Replier {

        String reply( final String /*Message*/ /*Exchange*/ request ) {
            out.println( "\n[ERROR] Expected: 'Re'quest', Actual: " + request
                    + "  <-- Am I doing somethig wrong, is this a bug or a feature?\n" );
            return String.format( "**** Replying to %s ****%n", request/*.getMessage()*/ /*.getBody( String.class )*/ );
        }
    } // Replier

    private static final DefaultCamelContext cc = new DefaultCamelContext();

    public static void main( final String... args ) throws Exception {

        final Replier replier = new RequestReplyMessageSample().new Replier();

        cc.setName( "Request Reply Sample" );
        cc.addRoutes( new RouteBuilder() {

            @Override
            public void configure() {

                from( "timer:start?repeatCount=1" )
                        .setExchangePattern( ExchangePattern.InOut )
                        .process().message( m -> m.setBody( "'Re'quest'" ) ) // EIP Request
                        .process().message( m -> print( "Request", m ) )
                        .log( "Requesting..." )
                        .log( "Replying..." )
                        // How to get Message (or Exchange) as argument in here?
                        .bean( replier, "reply(${body})" ) // EIP Requestor/Replier
                        .process().message( m -> print( "Reply", m ) ) // EIP Reply (in the body of the Message)
                        .setId( "Request/Reply" );
            }
        } );
        cc.start();
        Thread.sleep( 2000 );
        cc.stop();
        cc.close();
    } // main()

    static void print( final String endpoint, final Message m ) {

        out.printf( "%s %s: %s%n", endpoint, m, m.getBody() );
    } // print()

} // RequestReplyMessageSample

Output

...
Request Message: 'Re'quest'
[ple) thread #1 - timer://start] Request/Reply                  INFO  Requesting...
[ple) thread #1 - timer://start] Request/Reply                  INFO  Replying...

[ERROR] Expected: 'Re'quest', Actual: Re'quest  <-- Am I doing somethig wrong, is this a bug or a feature?

Reply Message: **** Replying to Re'quest ****
...
apaderno
  • 28,547
  • 16
  • 75
  • 90
Gerold Broser
  • 14,080
  • 5
  • 48
  • 107

2 Answers2

2

It's a feature. In this case, the single quotes at the start/end of the expression are interpreted as a string literal start/end. You need to add another single quote to let the parser see it as character (i.e. m.setBody("''Re'quest''")).

fvaleri
  • 638
  • 1
  • 4
  • 10
  • I believe you that this is a feature. However, neither the doc chapter nor the code you link says anything about apostrophe trimming (explicitely). Re the first: I'm not using any operator. I'm just setting a header with a string. Re the second: The `boolean singleQuotedLiteralText()` just checks and returns whether a text is single quoted. – Gerold Broser Dec 19 '20 at 10:20
  • It is not trimmed, it is simply interpreted as string literal start/end char, rather than apostrophe char. – fvaleri Dec 19 '20 at 10:27
1

This is because the body is passed as explicit method parameter to the bean.

The single quotes are preserved in the following scenarios:

  • pass the string as message body in the request
  • set (or overwrite) the body in the route (.setBody) as constant
  • set (or overwrite) the body in the route (.setBody) as expression
  • passing the body implicit to a bean
  • set (or overwrite) the body through a bean method return value
  • set (or overwrite) the body through a processor bean

Only when the body is passed explicitly to a bean method, the quotes are interpreted as string literal boundaries.

.bean(new EchoBean(), "echoBody(${body})")

becomes in your case

.bean(new EchoBean(), "echoBody('Re'quest')")

You can try this test class (Camel 3, JUnit 5). It fails because the quotes are lost in the last bean call with explicit parameters.

package test.camel;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;

class QuoteTest extends CamelTestSupport {
    public static final String MOCK_OUTPUT = "mock:output";

    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from( "direct:start" )
                        .log("Reveived body: ${body}")
                        .setBody(constant("'Re'quest'"))
                        .log("Body overwritten in route: ${body}")
                        .bean(new EchoBean())
                        .log("Body overwritten through bean: ${body}")
                        .process().message( m -> m.setBody( "'Re'quest'" ) )
                        .log("Body overwritten through processor: ${body}")
                        .bean(new EchoBean(), "echoBody(${body})")
                        .log("Body overwritten through bean with methodparameter: ${body}")
                        .to(MOCK_OUTPUT);
            }
        };
    }

    @Test
    void routeTest_quoteHandling_processed() throws Exception {
        getMockEndpoint(MOCK_OUTPUT).expectedBodiesReceived("'Re'quest'");
        template.requestBody("direct:start", "'Re'quest'");
        assertMockEndpointsSatisfied();
    }

    static class EchoBean {
        public String echoBody(final String messageBody) {
            System.out.println("Expected: 'Re'quest', Actual: " + messageBody);
            return messageBody;
        }
    }
}

It produces the following output. As you can see, the quotes are preserved through all steps except the last bean call with explicit parameter passing

09:00:53.521 [main] INFO  route1 - Reveived body: 'Re'quest'
09:00:53.521 [main] INFO  route1 - Body overwritten in route: 'Re'quest'
Expected: 'Re'quest', Actual: 'Re'quest'
09:00:53.527 [main] INFO  route1 - Body overwritten through bean: 'Re'quest'
09:00:53.527 [main] INFO  route1 - Body overwritten through processor: 'Re'quest'
Expected: 'Re'quest', Actual: Re'quest  <<-- only when the body is passed as method parameter, the quotes are lost
09:00:53.529 [main] INFO  route1 - Body overwritten through bean with methodparameter: Re'quest
burki
  • 6,741
  • 1
  • 15
  • 31