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.
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}");
}
};
}
}
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 !
Related
As part of upgrading spring jars we are upgrading spring dependencies from 2.5 to 4.3.0 version.
also updated apache camel jars from version 1.6.0 to 2.6.0 (camel-core, camel-jms, camel-spring)
the configuration was working fine before spring upgrade, please let me know if the information provided is not clear.
below are the current dependencies used in our project.
spring 4.3.0 ,
camel-core-2.6.0 ,
camel-jms-2.6.0 ,
camel-spring-2.6.0 ,
activemq-console-5.3.0.3a ,
activemq-core-5.3.0.3a ,
activemq-pool-5.3.0.3a ,
kahadb-fuse-5.3.0.3a ,
activemq-camel-fuse-5.3.0.3a
Camel Context Configuration looks like below:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
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-4.3.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring" errorHandlerRef="deadLetterErrorHandler">
<route>
<from uri="embeddedActiveMQ:DYNAMIC.INTERNAL.QUEUE?concurrentConsumers=3&maxConcurrentConsumers=100&cacheLevelName=CACHE_CONSUMER&maxMessagesPerTask=-1"/>
<to uri="dynamicRouter"/>
</route>
</camelContext>
<!-- Dynamic router bean delivers to external (message bus) component -->
<bean id="dynamicRouter" class="com.messagebus.client.DynamicEmbeddedRouter">
<constructor-arg index="0">
<value>aiAuditAMQ</value>
</constructor-arg>
</bean>
</beans>
DynamicEmbeddedRouter.java
import java.util.UUID;
import org.apache.camel.Exchange;
import org.apache.camel.Header;
import org.apache.camel.Message;
import org.apache.camel.RecipientList;
public class DynamicEmbeddedRouter
{
private String endpoint;
public DynamicEmbeddedRouter(String endpointName)
{
endpoint = (endpointName + ":");
}
#RecipientList
public String routeMessage(#Header(name="JMSCorrelationID") String destName, Exchange exchange) {
String destination = endpoint + destName;
exchange.getIn().setHeader("JMSCorrelationID", UUID.randomUUID().toString());
return destination;
}
}
below is the error we are seeing after upgrading the jars:
org.apache.camel.FailedToCreateRouteException: Failed to create route route at: >>> To[dynamicRouter] <<< in route: Route[[From[embeddedActiveMQ:DYNAMIC.INTERNAL.QUEUE?concurre... because of Failed to resolve endpoint: dynamicRouter due to: org.apache.camel.Header missing element value
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:759)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:160)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:701)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:1623)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:1412)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:1321)
at org.apache.camel.spring.SpringCamelContext.doStart(SpringCamelContext.java:164)
at org.apache.camel.impl.ServiceSupport.start(ServiceSupport.java:65)
at org.apache.camel.impl.ServiceSupport.start(ServiceSupport.java:52)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:1299)
at org.apache.camel.spring.SpringCamelContext.maybeStart(SpringCamelContext.java:203)
at org.apache.camel.spring.SpringCamelContext.onApplicationEvent(SpringCamelContext.java:101)
... 118 more
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: dynamicRouter due to: org.apache.camel.Header missing element value
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:449)
at org.apache.camel.util.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:47)
at org.apache.camel.model.RouteDefinition.resolveEndpoint(RouteDefinition.java:175)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:110)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:116)
at org.apache.camel.model.SendDefinition.resolveEndpoint(SendDefinition.java:64)
at org.apache.camel.model.SendDefinition.createProcessor(SendDefinition.java:58)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:403)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:174)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:756)
... 129 more
Caused by: java.lang.annotation.IncompleteAnnotationException: org.apache.camel.Header missing element value
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:81)
at com.sun.proxy.$Proxy85.value(Unknown Source)
at org.apache.camel.component.bean.BeanInfo.createParameterUnmarshalExpressionForAnnotation(BeanInfo.java:619)
at org.apache.camel.component.bean.BeanInfo.createParameterUnmarshalExpression(BeanInfo.java:599)
at org.apache.camel.component.bean.BeanInfo.createMethodInfo(BeanInfo.java:303)
at org.apache.camel.component.bean.BeanInfo.introspect(BeanInfo.java:219)
at org.apache.camel.component.bean.BeanInfo.introspect(BeanInfo.java:196)
at org.apache.camel.component.bean.BeanInfo.<init>(BeanInfo.java:94)
at org.apache.camel.component.bean.BeanProcessor.<init>(BeanProcessor.java:56)
at org.apache.camel.component.bean.BeanProcessor.<init>(BeanProcessor.java:60)
at org.apache.camel.spring.SpringCamelContext.convertBeanToEndpoint(SpringCamelContext.java:193)
at org.apache.camel.impl.DefaultCamelContext.createEndpoint(DefaultCamelContext.java:1981)
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:441)
... 138 more
Please help me to fix this error.
I created a camel route that reads an xml an puts a message in an ActiveMQ-Queue for every element in xml. All is working fine but the error-handling does not work. Here is the route:
#Override
public void configure() throws Exception {
from(fileIn)
.routeId(IN_ROUTE_ID)
.onCompletion()
.to(CommonRoutes.ENDPOINT_DIRECT_LOGGING)
.end()
.onException(UncategorizedJmsException.class)
.maximumRedeliveries(maxRetries)
.backOffMultiplier(multiplier)
.redeliveryDelay(initialDelay)
.end()
.unmarshal(jaxbDataFormat)
.process(fileProcessor)
.split(body()).stopOnException().shareUnitOfWork()
.process(domainWrapProcessor)
.to(ACTIVE_MQ_OUT + ":queue:" + checkNotNull(queueName))
.end()
;
}
And here the configuration of FileEndpoint:
public void init(){
this.setAutoCreate(false);
this.setFile(new File(checkNotNull(csvFolder)));
this.setCamelContext(checkNotNull(context));
this.setAntInclude(ANT_INCLUDE);
this.setMove(doneFolder);
this.setMoveFailed(errorFolder);
}
The intention is that on every exception the file is moved to moveFailed folder and in case of JMSException (ActiveMQ offline) camel should retry and if finally fails also move to moveFailed.
I have created a unit tests for both cases. here is the test for any exception:
#Test
public void testException throws InterruptedException {
amqMmock.setExpectedMessageCount(3);
amqMock.whenAnyExchangeReceived((e) -> {
throw new RuntimeException("");
});
assertMockEndpointsSatisfied();
Thread.sleep(1000);
errorContainsFile(true);
}
This test is passing the file is moved into error folder set. But this is not working if i run this route in real (camel blueprint on fuse):
The problem is that on any (not UncategorizedJmsException) exception the file just keeps locked (.camelLock file created). (thanks to stopOnException the desired behavior for JMSExceptions is working)
So how to get camel to move the file to moveFailed folder on any exception?
To the best of my knowledge, moveFailed will only actually move the file to the error-dir if something goes wrong within the file-component itself (at least what I've experienced). This would explain why your file is not moved to the error-dir upon hitting an exception.
What you could try to do is perhaps something like this:
.onException(UncategorizedJmsException.class)
.maximumRedeliveries(maxRetries)
.backOffMultiplier(multiplier)
.redeliveryDelay(initialDelay)
.to(errorFolder)
.end()
Here is how I would have set up your route using blueprint with XML rather than Java DSL (well, roughly, just to get the gist of it):
<!-- Redelivery Policy -->
<bean id="redeliveryPolicyConfig" class="org.apache.camel.processor.RedeliveryPolicy">
<property name="maximumRedeliveries" value="${redelivery.max.attempts}" />
<property name="redeliveryDelay" value="${redelivery.delay.ms}" />
<property name="logRetryAttempted" value="${redelivery.log.attempts}" />
</bean>
<!-- Error Handler -->
<bean id="errorHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
<property name="deadLetterUri" value="direct:error" />
<property name="useOriginalMessage" value="true" />
<property name="redeliveryPolicy" ref="redeliveryPolicyConfig" />
</bean>
<camelContext>
<route id="IN_ROUTE_ID">
<from uri="file://{{fileIn}}?move={{doneFolder}}&moveFailed={{errorFolder}}" />
...
<to uri="activemq:queue:{{queueName}}" />
</route>
<route id="error-route">
<from uri="direct:error" />
<to uri="file://{{errorFolder}}" />
</route>
</camelContext>
So, now I am attempting to import routes from an XML file into the Java DSL.
I've been attempting to start with this link but since it's such a simple example, it doesn't really help me and doesn't point me to a more complicated example.
My problem is that my Camel routes use beans. Beans for the PropertiesComponent and FileIdempotentRepository and others are defined within the XML file for use by the routes in the XML file.
My original Spring configuration looked something like the following:
<?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-4.2.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="bean1" class="class1" />
<bean id="bean2" class="class2" />
<bean id="bean3" class="FileIdempotentRepository"> [...] </bean>
<bean id="properties" class="PropertiesComponent"> [...] </bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="{{someplace}}&filter=#bean1" />
<setHeader headerName="FileRepoKey">
<simple>${file:name}-${file:modified}</simple>
</setHeader>
<idempotentConsumer messageIdRepositoryRef="bean3">
<header>FileRepoKey</header>
<process ref="bean2" />
<to uri="{{otherplace}}"/>
</idempotentConsumer>
</route>
</camelContext>
</beans>
So how do I convert this mess into something usable by the Java DSL to import routes from?
I understand from looking at that link that I need to do something like convert <camelContext> to <routes>. But leaving in the beans gives me an error along the lines of:
Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.springframework.org/schema/beans", local:"beans"). Expected elements are [...]
What do I need to change? Or can I not have beans in the XML file in order for it to be imported by the Java used in the link?
I guess I should've asked this a different way and maybe someone would have thought of this way.
It may give you all nightmares, I'm not sure. Be warned.
So since the concept is "have things potentially run from an XML file alongside Java" the following end result came about:
public static void main(String[] args) throws Exception {
Main main = new Main();
//the XML file has a CamelContext in it.
main.setApplicationContextUri("myRoutes.xml");
main.start();//instantiates the CamelContext so we can use it in Java
List<CamelContext> camelContexts = main.getCamelContexts(); //should only have 1 item in the list
CamelContext context = camelContexts.get(0);
//in order to add a component to the registry the following is needed for set up
// afterwards, should just be able to add anything to the registry with registry.put("name", object)
final SimpleRegistry registry = new SimpleRegistry();
final CompositeRegistry compositeRegistry = new CompositeRegistry();
compositeRegistry.addRegistry(context.getRegistry());
compositeRegistry.addRegistry(registry);
((DefaultCamelContext) context).setRegistry(compositeRegistry);
final FileIdempotentRepository myFileStore = new FileIdempotentRepository();
File myFile = new File("idempotentRepoFiles/myFileStore.txt");
final TimeStampFileFilter<?> myFileFilter = new TimeStampFileFilter<Object>(0L);
registry.put("myFileFilter", myFileFilter);
//512MB
myFileStore.setMaxFileStoreSize(536870912L);
myFileStore.setFileStore(myFile);
myFileStore.setCacheSize(100000);
//add a route to the CamelContext that was initially created in the XML file
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
onException(myException.class)
.handled(true);
onException(GenericFileOperationFailedException.class)
.onException(SocketException.class)
.maximumRedeliveries(2)
.redeliveryDelay(5000L)
;
Processor myProcessor = new myProcessor();
from("{{myStart}}&filter=#myFileFilter")
.setHeader("myFileRepoKey", simple("${file:name}-${file:modified}"))
.idempotentConsumer(header("myFileRepoKey"), myFileStore)
.process(myProcessor)
.to("{{myEnd}}")
;
}
});
context.start();
main.run();
}
Basically: create a CamelContext in the Spring XML file, initialize it, grab it, modify it to include routes built in Java.
Route definition in Camel can be XML based (Spring DSL or Blueprint DSL) or Java based (Java DSL). A route definition can be expressed equally in both languages.
In a Spring application you can define your beans in a file and your routes in other files which you import. Routes defined in external files can refer to beans defined in your main file.
spring-main.xml
<?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-4.2.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="bean1" class="class1" />
<bean id="bean2" class="class2" />
<bean id="bean3" class="FileIdempotentRepository"> [...] </bean>
<bean id="properties" class="PropertiesComponent"> [...] </bean>
<import resource="camel-routes.xml"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<routeContextRef ref="ExternalRoutes"/>
</camelContext>
</beans>
camel-routes.xml
<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-4.2.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routeContext id="ExternalRoutes" xmlns="http://camel.apache.org/schema/spring">
<route id="ARoute">
<from uri="direct:startHere" />
<to uri="bean:bean3" />
</route>
</routeContext>
</beans>
You can import more than one external file, of course. Just name each RouteContext differently.
If you modify one of the RouteContexts you must then restart your application. If you need a more dynamic application, try using an OSGi container to run your Camel routes, so you can easily modularize your application and add/remove features at runtime.
I'm new to ActiveMQ (version 5.9.1) and Apache Camel. I'm experimenting about a couple of routes. I wrote them in Java, then packed in a .jar and deployed on %ACTIVEMQ_HOME%/lib. In my custom foo-activemq.xml I added a camelContext tag with a package child tag. Here is my relevant .xml
...
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<package>edu.foo.amq.camel</package>
</camelContext>
...
And here are my two routes:
package edu.foo.amq.camel;
import org.apache.camel.builder.RouteBuilder;
public class NumberRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("jms:queue:number.queue")
.marshal("UTF-8")
.choice()
.when(header("readyToGo").isNotEqualTo(true))
.to("jms:queue:big.number.queue");
}
}
and
package edu.foo.amq.camel;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
public class BigNumberRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("jms:queue:big.number.queue")
.marshal("UTF-8")
.split(body().tokenize("\n")).streaming()
.process(new Processor() {
#Override
public void process(Exchange arg0) throws Exception {
arg0.getIn().setHeader("readyToGo", true);
System.out.println(arg0.getIn().getBody(
String.class));
}
})
.to("jms:queue:number.queue");
}
}
When I start my ActiveMQ broker I can see ... Total 0 routes, of wich 0 is started.. If I look at the ActiveMQ web console I can se the queues number.queue and big.number.queue up and running but my java routes don't. What am I missing?
UPDATE:
I remove the camelContext tag from my foo-activemq.xml configuration file and add the import tag instead:
...
<import resource="jetty.xml"/>
<import resource="foo-camel.xml"/>
...
Here is my foo-camle.xml configuration file, I largely use the %ACTIVEMQ_HOME%/examples/conf/camel.xml file. I put this file into %ACTIVEMQ_HOME%/conf:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<package>edu.foo.amq.camel</package>
</camelContext>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" >
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://amq-broker?create=false"/>
<property name="userName" value="${activemq.username}"/>
<property name="password" value="${activemq.password}"/>
</bean>
</property>
</bean>
but the result is the same: ActiveMQ says no routes
The Camel configuration XML file must be added to the activemq.xml configuration file:
<import resource="foo-activemq.xml" />
EDIT:
What else?
Rename foo-activemq.xml to the default activemq.xml
Verify again if your jar is really in the lib directory (I am sure you have done that already)
Add a simple test route to foo-camel-xml and check in the log file if this route is loaded, e.g.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring" >
<package>edu.foo.amq.camel</package>
<route>
<from uri="direct:start" />
<log message="${body}" />
</route>
</camelContext>
I am developing client server application using spring mvc and rest.
Its simple calculator service in which client calls the methods from server to execute operations.
This is my rest client code restClient.java:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.blog.samples.client;
/**
*
* #author bhushan.baviskar
*/
import com.blog.samples.domain.Calculator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
public class restClient {
public static void main(String [] args)
{
restClient tmp = new restClient();
tmp.calltoserver();
}
public void calltoserver() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("../../../../appContext.xml", restClient.class);
RestTemplate restTemplate = applicationContext.getBean("restTemplate", RestTemplate.class);
String url = "http://localhost:8080/rest/calc/4&3&+";
Calculator calObj = (Calculator) restTemplate.getForObject(url, Calculator.class);
System.out.println("details " + calObj.getDetails());
System.out.println("done");
}
}
And this is my appContext.xml file :
<?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.xsd">
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<bean id="messageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
</property>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="Calculator">com.blog.samples.webservices.rest.CalcController</prop>
</props>
</property>
</bean>
</beans>
I am getting response in json format but when I execute the restclient.java file it says :
DEBUG: [Dec-11 16:54:39,706] web.client.RestTemplate - GET request for "http://localhost:8080/rest/calc/4&3&+" resulted in 200 (OK)
Exception in thread "main" org.springframework.web.client.RestClientException: **Could not extract response: no suitable HttpMessageConverter found for response type** [com.blog.samples.domain.Calculator] and content type [text/plain;charset=UTF-8]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:84)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:199)
at com.blog.samples.client.restClient.calltoserver(restClient.java:27)
at com.blog.samples.client.restClient.main(restClient.java:21)
------------------------------------------------------------------------
I am new to the Spring Rest client Development so any help will be appreciated.
If anyone knows pl. tell me How to handle the response?
This is because the MappingJacksonHttpMessageConverter is not registered to your restTemplate.
By default all types of MessageConverters present in your classpath will be registered.
You should either remove property messageConverters for bean restTemplate in you xml to have default messageconverters or you have to add MappingJacksonHttpMessageConverter to your messageConverters list in your xml.
Hope this helps