2
votes

I'm currently trying the new REST DSL of the Apache Camel 2.14.0 release. And as the title of this post state it, I got a conflict with a String bean. Let's show what's wrong.

Here is a valid XML file reduced to a test case. It only defines a String bean and a Camel context containing a rest endpoint and a single route called by the rest endpoint.

<?xml version="1.0" encoding="UTF-8"?>
<beans
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://camel.apache.org/schema/spring
                           http://camel.apache.org/schema/spring/camel-spring.xsd"
>

    <bean id="source-directory" class="java.lang.String">
        <constructor-arg type="java.lang.String" value="file:/opt/a/directory/data/audio" />
    </bean>

    <camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">

    <dataFormats>
        <json id="jack" library="Jackson" unmarshalTypeName="org.apache.camel.component.jackson.TestPojo"/>
    </dataFormats>

    <restConfiguration bindingMode="json" component="restlet" port="5117" />

    <rest path="/rest-api/">
        <get uri="/{words}/" consumes="application/json" produces="application/json">
            <to uri="direct:words" />
        </get>       
    </rest>

    <route>
        <from uri="direct:words" />
        <transform>
            <simple>${headers.words}</simple>
        </transform>
    </route>

    </camelContext>

</beans>

To load and test this Camel context I use the following test case:

import org.apache.camel.CamelContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Test {
       @org.junit.Test
       public void testT() throws Exception {
               final FileSystemXmlApplicationContext bean = new FileSystemXmlApplicationContext("src/test/resources/camelContext.xml");
               final CamelContext context = bean.getBean("camelContext", CamelContext.class);
               context.start();
               Thread.yield();
               Thread.sleep(600000);
       }
}

It currently lead to the following error :

org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> RestBinding <<< in route: Route(route2)[[From[rest:get:/rest-api/:/{words}/?produces=a... because of Provider com.sun.xml.bind.v2.ContextFactory could not be instantiated: javax.xml.bind.JAXBException: "file" ne contient pas ObjectFactory.class ou jaxb.index

That is, "file" does not contain ObjectFactory.class or jaxb.index

It seems that removing the source-directory bean declaration OR the rest endpoint declaration solves the problem, so it seems there is an incompatibility between them; but, as a Camel newbie, I'm unable to figure out what the problem is.

Can someone give me clues? Am I doing something wrong?

Thanks in advance, Arthur.

2

2 Answers

1
votes

I believe this issue is occurring due to the mechanism through which you are loading your Spring and Camel contexts for your unit test. Consider instead using CamelTestSupport.

I rewrote this test using this paradigm and everything worked just fine.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/META-INF/spring/camel-context.xml" })
public class Test extends CamelTestSupport {
    @org.junit.Test
    public void testT() throws Exception {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        CloseableHttpResponse response = httpClient.execute(new HttpGet(
                        "http://localhost:5117/rest-api/hello"));
        assertEquals(200, response.getStatusLine().getStatusCode());
        assertEquals("\"hello\"", new BufferedReader(new InputStreamReader(response.getEntity()
                        .getContent(), StandardCharsets.UTF_8)).readLine());

    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder()
        {
            @Override
            public void configure() throws Exception {
                from("direct:words").transform().simple("${headers.words}");
            }
        };
    }
}
0
votes

Thanks to a teammate, I finally understood the error.

Problem come from the definition of a "java.lang.String" bean in the camel context. When putting

<bean id="source" class="java.lang.String">
    <constructor-arg type="java.lang.String" value="file:/opt/a/directory/data/audio" />
</bean>

in the camel context I got the following log :

[main] JaxbDataFormat INFO Creating JAXBContext with contextPath: file:/opt/a/directory/data/audio and ApplicationContextClassLoader: sun.misc.Launcher$AppClassLoader@3485def8

My understanding of the situation is that if any java.lang.String object is defined it is then used by the JAXBContext as a factory identifier. They probably seek for an @Autowired String attribute that is normally always null. Replacing "source" bean by a bean that encapsulate my sting in an attribute solve the problem.

Unexpected side effect discovered !