Moving Camel Spring XML to Spring Boot - spring-boot

I would like to move several of our camel application to Spring Boot. Most of the examples I find are using the java dsl. The application we currently support are all based on Spring XML.
What steps should I take to migrate these application to Spring Boot. If I use FatJarRouter it is my understanding that a camel context is auto-cofigured already, so it seems to me I should be able to just define routes in spring xml.
#SpringBootApplication
#ImportResource("classpath:camel-context.xml")
public class CamelApplication extends FatJarRouter {
public static void main(String[] args) {
SpringApplication.run(CamelApplication.class, args);
}
#Bean
String myBean() {
return "I'm Spring bean!";
}
}
camel-context.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.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="test">
<from uri="timer://trigger"/>
<transform>
<simple>ref:myBean</simple>
</transform>
<to uri="log:out"/>
</route>
</routes>
</beans>
Exception
2015-11-13 15:59:13.734 WARN 2156 --- [on(5)-127.0.0.1] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Cannot locate BeanDefinitionParser for element [routes]
Offending resource: class path resource [camel-context.xml]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.fatal(FailFastProblemReporter.java:60) ~[spring-beans-4.2.2.RELEASE.jar:na]
at org.springframework.beans.factory.parsing.ReaderContext.fatal(ReaderContext.java:68) ~[spring-beans-4.2.2.RELEASE.jar:na]

See the bottom of this page how to include XML routes:
https://cwiki.apache.org/confluence/display/CAMEL/Spring+Boot

Related

Having to use deprecated classes with Spring MVC

Have been trial Spring Web MVC (4.2.5) and have his a number of issues trying to use a DispatcherServlet and
<mvc:annotation-driven />
Have setup a simple #Controller class and wanted to use the POJO to JSON mapping. The docu said that if Jackson was detected on the class path it would be used automatically, however this didn't work for me and I was forced to use the 'deprecated' AnnotationMethodHandlerAdapter
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
which then worked fine.
Equally, tried to create a #ControllerAdvice class for handling all exceptions, but only got an #ExceptionHandler method working on the same controller class, and that was only when I added the (again) deprecated AnnotationMethodHandlerExceptionResolver to the context.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
Having to instantiate two deprecated classes suggests I am doing something wrong, especially when all the tutorials seem to suggest this should all 'just work', but I cannot see what (and indeed nosing through the Spring source I cannot see how the default and recommended handlers would work anyway)
There are no errors, the annotation simply aren't detected. The fill context xml is
please find the entire context XML below (is very simple)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven enable-matrix-variables="true"/>
<bean name="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters" ref="mappingJackson2HttpMessageConverter"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />
<context:component-scan base-package="com.domain.datastore.dao"/>
<context:component-scan base-package="com.domain.service"/>
<context:component-scan base-package="com.domain.uiapi"/>
</beans>
An example controller is
#RestController("/place/*")
public class PlaceController {
private PlaceService placeService;
#Autowired
public PlaceController(PlaceService placeService) {
this.placeService = placeService;
}
#RequestMapping(path="/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model) {
return placeService.getPlace(id);
}
}
and the cross-cutting exception handler is
#ControllerAdvice
public class GlobalExceptionController {
public GlobalExceptionController() {
System.out.println("GlobalExceptionController");
}
#ResponseStatus(HttpStatus.NOT_FOUND)
#ExceptionHandler(NotFoundException.class)
public ModelAndView handleCustomException(NotFoundException ex) {
return null;
}
}
The issue was that Spring MVC was matching the path in
#RestController("/place/*")
And as such passing the instance of PlaceController around as the handler. The ExceptionHandlerExceptionResolver expects a HandlerMethod and so was unable to process the exception.
As such dropping the path from the class annotation and putting the full path in the method got it all working and I dropped all the deprecated beans.
#RestController
public class PlaceController {
#RequestMapping(path="/place/{id}", method = RequestMethod.GET)
public #ResponseBody Place getPlace(#PathVariable("id") long id, Model model)
What I am not sure is if this is a bug. Shouldn't it be possible to put the 'base' path in the RestController annotation and the subpath in the RequestMapping?
As far as I can understand you don't want to use a deprecated class. AnnotationMethodHandlerAdapter is indeed Deprecated. As doc suggest you should use RequestMappingHandlerAdapter instead.
See here for the details.
And instead of AnnotationMethodHandlerExceptionResolver you can use ExceptionHandlerExceptionResolver.

Spring property place holder is not resolving in jaxws:client (cxf) address property

Environment:
Spring MVC : 4.1.7.RELEASE
CXF: 3.0.0
java: 1.8
web.xml --- loads appContext.xml (spring cofigs) & cxfContext.xml (configs for cxf)
spring-servlet.xml --- loading the spring mvc configs.
I'm using the below way to load the properties file.
#Configuration
#PropertySource(value = { "classpath:config.properties" })
public class Configuration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Properties are getting resolved and no issues except in one case.
I'm using CXF for webservices and the address property is not getting resolved when "${addressVal}" is used. All other properties inside the xml are gettign loaded except for "jaxws:client".
<jaxws:client id="port"
serviceClass="com.service.Myclass"
address="${addressVal}" />
Where is the problem. What I'm doing wrong.
Problem with servlet context / application context loading ?
Please advice.
I am having the same problem. Sadly no solution found yet. However, for anyone finding this question, a workaround is using the JaxWsProxyFactoryBean.
Example:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
<bean id="client" class="demo.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="demo.spring.service.HelloWorld"/>
<property name="address" value="${some.property.value}"/>
</bean>
It is not as nice, becuase you have to inject the factory, call create() and cast, but at least it works.
#Autowired
#Qualifier("clientFactory")
private JaxWsProxyFactoryBean factory;
public void callService() {
HelloWorld helloWorld = (demo.spring.service.HelloWorld)factory.create();
}
You can also add the following to your spring config to create a specific bean, but that did not work for me. Trying to inject that bean failed, which is why I settled on the method described above.
<bean id="client" class="demo.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
See also http://cxf.apache.org/docs/writing-a-service-with-spring.html at the bottom of the page

Cannot get external file properties loaded in Context

I'm setting up a project using Spring 3.2.9.FINAL and I'm just unable to load some properties I've stored in an external file. That's how my application-context.xml looks:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:property-placeholder
location="file:/home/myapp/settings.properties" />
<bean class="foo.Test">
<property name="property" value="${test.property}" />
</bean>
</beans>
That's the content of my settings.properties file:
test.property=Hello world
The foo.Test class is very simple and only contains a String property. In my main method I do this:
public class App {
public static void main(String[] args) {
DefaultListableBeanFactory dlbf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(dlbf);
reader.loadBeanDefinitions(new ClassPathResource(
"/application-context.xml", Test.class));
System.out.println(dlbf.getBean(Test.class).getProperty());
}
}
That's what I get when executing it:
Jun 12, 2014 12:03:38 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [application-context.xml]
${test.property}
I tried several workarounds based in answers from SO, but nothing seems to work. What am I doing wrong?
You are loading beans into a BeanFactory whereas you should use an ApplicationContext.
public class App {
public static void main(String[] args) {
ApplicationContext ctx d= new ClassPathXmlApplicationContext("application-context.xml");
System.out.println(ctx.getBean(Test.class).getProperty());
}
}
See the reference guide for an explanation of the differences.
Application context loads all beans from spring XML file and doesn't support selective lazy loading but using XML bean factory version (check precise class name ) one can selectively load beans. Please test.

Spring bean not injected into CXF web service, Why?

I am writing a RESTful service (using CXF on JBoss) in which I have inject another class using Spring (Autowired). But the class is not getting injected and is null.
Web Service Interface and Class (Where injection needs to happen)
package com.company.project.web;
#Path("/myws")
public interface IMyWebService {
#POST
#Path("/doSomething")
#Consumes("application/json")
#Produces("application/json")
MyResponse doSomething(MyRequest myRequest)
}
#Service("myWebService")
public class MyWebService implements IMyWebService {
#Autowired
private IMyCore myCore;
public MyResponse doSomething(MyRequest myRequest) {
....
}
}
That which has to be injected
package com.company.project.biz;
public interface IMyCore {
MyResponse doSomething(MyRequest myRequest);
}
#Component("myCore")
public class MyCore implements IMyCore {
public MyResponse doSomething(MyRequest myRequest) {
.....
}
}
Beans.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"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<context:annotation-config />
<context:component-scan base-package="com.company.project"/>
<jaxrs:server id="myWebService" address="/">
<jaxrs:serviceBeans>
<bean class="com.company.project.web.MyWebService" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json" />
</jaxrs:extensionMappings>
</jaxrs:server>
</beans>
My service is active (http://localhost:8080/{warname}/myws/doSomething) but the MyCore instance is not being injected into MyWebService (in the myCore field). It is always null and my service does not work as expected, instead throws NullPointerException
Tried all inputs gathered over google. No luck! Your help is highly appreciated.
Regards
Try to add below method to your web service:
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
The current web application context (usually the one loaded by ContextLoaderListener) will be used for autowiring, so the IMyCore bean has to be defined in the context listener configuration file and not in the web service one.
If you want to use Spring Beans in CXF Web Service class, then declare WebService as following in the XML configuration file of the CXF (e.g. spring-cxf.xml)
<bean id="hello" class="demo.spring.service.HelloWorldImpl" />
<jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />
Declare separated bean for the WebService class and then put it in the endpoint with an ID. Like this you will have spring managed bean, where you can use AutoWired annotations as well.
Your beans never won't be injected automatically if you will declare your web service as following.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
In this case you will need either:
Inject spring beans manually
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
Or retrieve the beans one by one from the spring context
ApplicationContext context = ...; // your Spring ApplicationContext
HelloBean helloBean = (HelloBean) context.getBean("bean");
I haven't tried this for JAX-RS, but the approach in my opinion should be the same.
From CXF official documentation.
Try to add below bean configuration at Beans.xml
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
In my case, it worked..

Spring and auto-wiring: NullPointerException

I'm trying to get a grip on auto-wiring in Spring, but I can't seem to properly instantiate the bean (a DocumentBuilder). I have created a custom JSP tag as such:
public class MyTag extends SimpleTagSupport {
#Autowired
private DocumentBuilder documentBuilder;
public void setBuilder(DocumentBuilder builder) {
this.documentBuilder = builder;
}
#Override
public void doTag() throws IOException {
// documentBuilder is null in here!
}
}
This is the servlet configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scan for HTTP/REST controllers -->
<context:component-scan base-package="the.right.package" />
<context:annotation-config/>
<bean id="documentBuilderFactory"
class="javax.xml.parsers.DocumentBuilderFactory"
factory-method="newInstance">
<property name="validating" value="false" />
<property name="ignoringElementContentWhitespace" value="true" />
</bean>
<bean id="documentBuilder" class="javax.xml.parsers.DocumentBuilder"
factory-bean="documentBuilderFactory"
factory-method="newDocumentBuilder">
</bean>
</beans>
Any ideas?
You can only inject in spring beans! But Jsp-Tags are no Spring Beans, so the Autowird annotation will be completely ignored, and therefore the field is null.
There are two solution:
use the #Configurable Support. -- But that requires real AspectJ. (I have never tried it for Tags, but I guess it will work for tags like for every other normal class). #see Spring Reference: Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
Extend your tag from the abstract Spring class RequestContextAwareTag. This provides access to the WebApplicationContext via getRequestContext().getWebApplicationContext(). Then you can use the WebApplicationContext to obtain the required beans programmatic.
Try to modify the code like this
public class MyTag extends SimpleTagSupport {
private DocumentBuilder documentBuilder;
#Autowired
public void setBuilder(DocumentBuilder builder) {
this.documentBuilder = builder;
}
#Override
public void doTag() throws IOException {
// documentBuilder is null in here!
}
}
You can use #Autowired if you mark your tag class as Spring bean. But it's stupid, because simple tags not caching by container. Each request creates own tag instance, but wiring happend only conteiner starts.

Resources