This is likely to be a misconception on my part when it comes to working with SpringBoot on FUSE EAP environments. I've been trying to deploy a service, which I've developed following the RedHat documentation and the archetypes/examples I've found online that mix Camel and SpringBoot, but to no avail.
From what I understand, when creating a connection to a JNDI datasource, which has been configured and tested in the EAP Fuse server, I can use the application.properties, or application.yml, to have the spring application autoconfigure the connection. In my case, it's required that I use #PersistenceContext to invoke the EntityManager, since the CRUD operations that the extending JpaRepository don't really cover the needs.
As per RedHat's documentation, FUSE 7.2 has been installed in EAP 7.1 and the POM is using the org.jboss.redhat-fuse.fuse-springboot-bom version 7.2.0.fuse-720020-redhat-00001.
I've tried using spring's autoconfiguration, a manual configuration declaring a #Configuration class, a manual configuration by declaring the database connection in the camel-context.xml file, and some other minor tests.
The errors vary depending on whether I try delpying the .jar or .jar.original, generated by having the spring-boot-maven-plugin with the repackage execution goal, errors obtained up to this point are:
NullPointer because EntityManager em is null (.jar.original)
java.lang.NoClassDefFoundError: org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder (.jar.original, when there's a manual configuration of the datasource, be it in a #Configuration annotated java class, or in the camel-context.xml using Spring DSL)
java.lang.ClassNotFoundException: com.example.dao.genericDAOImpl (.jar with all dependencies packaged)
Here are snippets of my program, which include the POM, Application.java and the component which is trying to get the EntityManager, will be happy to provide more snippets if it's not enough/unclear.
POM.xml
...
<properties>
<fuse.version>7.2.0.fuse-720020-redhat-00001</fuse.version>
...
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
...
<build>
<defaultGoal>spring-boot:run</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.16.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
application.properties
spring.datasource.jndi-name=jdbc:sqlserver://ip:1433;DatabaseName=dbname
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.generate-ddl=false
Application.java
#ImportResource({"classpath:spring/camel-context.xml"})
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
camel-context.xml
<beans ...>
...
<camelContext id="identidades_financieras" xmlns="http://camel.apache.org/schema/spring">
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<setHeader headerName="Exchange.HTTP_RESPONSE_CODE">
<constant>500</constant>
</setHeader>
<setBody>
<simple>${exception.message}</simple>
</setBody>
</onException>
<restConfiguration apiContextPath="/openapi.json"
bindingMode="json" component="undertow"
contextPath="/restservice/api_v1" enableCORS="true">
<dataFormatProperty key="prettyPrint" value="true"/>
</restConfiguration>
<rest enableCORS="true" id="rest-for-openapi-document" path="/openapi">
<get id="openapi.json" produces="application/json" uri="openapi.json">
<description>Gets the OpenAPI document for this service</description>
<route id="route-for-openapi-document">
<setHeader headerName="Exchange.CONTENT_TYPE" id="setHeader-for-openapi-document">
<constant>application/vnd.oai.openapi+json</constant>
</setHeader>
<setBody id="setBody-for-openapi-document">
<constant>resource:classpath:openapi.json</constant>
</setBody>
</route>
</get>
</rest>
<rest bindingMode="auto" enableCORS="true"
id="rest-b5d099c1-1996-458b-b5db-34aadc57a548" path="/">
<get id="customPaginatexxxVO" produces="application/json" uri="/xxx">
<to uri="direct:customPaginatexxxVO"/>
</get>
...
<route id="route-28f4489d-b354-401b-b774-6425bec1c120">
<from id="from-17c4205f-8d28-4d3d-a265-cb1c38c9bc32" uri="direct:customPaginatexxxVO"/>
<log id="customPaginatexxxVO-log-1" message="headers ====> pageSize: ${header.pageSize} - pageNumber: ${header.pageNumber}"/>
<bean id="to-ee6565efaf-de46-4941-b119-be7aaa07d892"
method="paginate" ref="genericService"/>
<log id="customPaginatexxxVO-log-2" message="${body}"/>
</route>
<beans/>
genericService.java
#Service
public class genericServiceImpl implements genericService {
#Autowired
private genericDAO dao;
...
#Override
public xxxVO paginate(Map<String, Object> reqHeaders) {
... pageProps are defined using reqHeaders ...
xxxVO paginated = dao.customPagination(pageProps);
return paginated;
}
...
}
genericDAOImpl.java, which errors out when anything regarding em is invoked.
#Repository
public class genericDAOImpl implements genericDAO {
#PersistenceContext //when manually configured, I've added the (unitName="") in reference to the persistence unit, from my understanding, since only one datasource was created, this should pick up by default
private EntityManager em;
...
#Override
public xxxVO customPagination(paginateProps pageProps) {
xxxVO result = null;
try {
CriteriaBuilder paginationBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> paginationQuery = paginationBuilder.createQuery(entity.class);
Root<T> entityClass = paginationQuery.from(entity.class);
paginationQuery.select(entityClass);
... some settings with pageProps ...
TypedQuery<T> query = em.createQuery(paginationQuery);
entityList = query.getResultList();
... entityList is transformed to xxxVO ...
} catch (Exception e) {
LOG.error("caught something");
e.printStackTrace();
}
return result;
}
...
As stated before, I've been getting numerous different errors depending on the options I've tried, and most of them clearly come down to misconfiguration, or not deploying correctly, I'm still somewhat inexperienced when it comes to SpringBoot and Camel, and different things I've read on the internet have created some confusion. Just to make sure, the pagination method, while very snipped out, should be working, if it had a not nulled EntityManager.
Here are a couple of the logs:
When deplying .jar (fat jar with all dependencies), which from the tests I've made, deploys correctly using java -jar, but not in the fuse eap service
09:16:01,937 WARN [org.springframework.context.support.GenericApplicationContext] (MSC service thread 1-3) Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.example.dao.genericDAOImpl] for bean with name 'genericDAO' defined in URL [vfs:/content/identidades_financieras-1.0-SNAPSHOT.jar/BOOT-INF/classes/spring/camel-context.xml]; nested exception is java.lang.ClassNotFoundException: com.example.dao.genericDAOImpl from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
09:16:01,940 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-3) MSC000001: Failed to start service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": org.jboss.msc.service.StartException in service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": Cannot create camel context: identidades_financieras-1.0-SNAPSHOT.jar
at org.wildfly.extension.camel.service.CamelContextActivationService.start(CamelContextActivationService.java:71)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:2032)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1955)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.example.dao.genericDAOImpl] for bean with name 'genericDAO' defined in URL [vfs:/content/identidades_financieras-1.0-SNAPSHOT.jar/BOOT-INF/classes/spring/camel-context.xml]; nested exception is java.lang.ClassNotFoundException: com.example.dao.genericDAO from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
...
When deploying .jar.original (basically, just the java) with a manually configured DataSource and EntityManagerFactory. From what I understand, the service is expecting org.springframework.boot dependencies to exist on the server. After checking the modules, there is no org.springframework.boot module in the fuse layer. Is this intended?
09:50:17,265 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-8) MSC000001: Failed to start service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": org.jboss.msc.service.StartException in service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1978)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethods(Class.java:1975)
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:613)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:524)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:510)
at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:570)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:697)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:640)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:609)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1490)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:425)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:395)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
at org.wildfly.extension.camel.SpringCamelContextBootstrap$1.run(SpringCamelContextBootstrap.java:90)
at org.wildfly.extension.camel.proxy.ProxyUtils$1.invoke(ProxyUtils.java:51)
at com.sun.proxy.$Proxy68.run(Unknown Source)
at org.wildfly.extension.camel.proxy.ProxyUtils.invokeProxied(ProxyUtils.java:55)
at org.wildfly.extension.camel.SpringCamelContextBootstrap.createSpringCamelContexts(SpringCamelContextBootstrap.java:87)
at org.wildfly.extension.camel.service.CamelContextActivationService.start(CamelContextActivationService.java:58)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:2032)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1955)
... 3 more
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:412)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:400)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
... 27 more
Finally, when uploading the .jar.original using only the Spring autoconfigure, the EM is null, using Postman I get a status 500 and "No response available" when I consume the REST
java.lang.NullPointerException
at com.example.dao.genericDAOImpl.customPagination(GenericDAOImpl.java:252)
The line makes reference to CriteriaBuilder paginationBuilder = em.getCriteriaBuilder(), or any other place where a EM method is invoked.
Thank you for your time! Any comment is appreciated...
There is no support for Spring Boot with Fuse EAP and the Camel subsystem. Hence why you do not see any org.springframework.boot dependencies in the Fuse module layer.
If you are going to deploy Camel Spring Boot applications into EAP, it's best you either disable the Camel subsystem for your deployment or avoid installing the subsystem entirely.
This is by no means a solution to the issue I was having, I believe this to be but a temporary patch on my code since the 7.4 version of Fuse will supposedly support SpringBoot 2.1.x or something of the like, but doing the following allowed me to create the database connection and move on with my life. I will not mark this as the acceptable answer, unless I'm told that this is the only way.
In the Application.java, I straight up disabled the SpringBootServletInitializer. Full disclosure, I straight up have no idea of the impact that doing this could have in an application, but the dependency was troubling while I was trying to deploy.
#ImportResource({"classpath:spring/camel-context.xml"})
#SpringBootApplication
public class Application {//extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I created a persistence.xml file where I configured the name of persistence unit and selected the package containing the entities (or listed them, both worked).
In the camel-context.xml I declared the following before the tag
<bean class="org.apache.camel.component.jpa.JpaComponent" id="jpa">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="transactionManager" ref="jpaTxManager"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jpaTxManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="PERSISTENCE UNIT NAME IN PERSISTENCE.XML"/>
</bean>
<bean class="org.apache.camel.spring.spi.SpringTransactionPolicy" id="requiredPolicy">
<property name="transactionManager" ref="jpaTxManager"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
I created a java class responsible for the creation of the EntityManager, it is very important that the class is #Stateless (EJB), and that the connection to the persistence unit is made static.
#Stateless
public class persistenceUnitEntityManagerImpl implements IfEntityManager{
private static EntityManager em;
static {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE UNIT NAME");
em = entityManagerFactory.createEntityManager();
}
public void setEntityManager( EntityManager em ) {
persistenceUnitEntityManagerImpl.em = em;
}
public EntityManager getEntityManager() {
return persistenceUnitEntityManagerImpl.em;
}
}
In the beans where the database connection was needed, in my case, an #Component (should work just as well in a #Repository), I added the following:
private IfEntityManagerImpl IfEntityManager;
#PostConstruct
public void init() {
this.persistenceUnitEntityManagerImpl = new persistenceUnitEntityManagerImpl();
}
And whenever the EntityManager needs to be called, I can use persistenceUnitEntityManagerImpl.getEntityManager()
Just to make sure that the component isn't creating a new connection/entity manager/whatever, you can add a LOG to the #PostConstruct init, if your bean is a singleton (should be by default, I believe) you will never get that LOG or printline.
Base Facts : Apache Camel 2.20.1 (Spring Boot)
Multiple context reference in same spring boot config xml throws below highlighted error, despite providing explicit different ids
When my own example failed - I tried with simple sample case.. but met with the same error
Error creating bean with name 'typeConverter' defined in class path resource >[org/apache/camel/spring/boot/TypeConversionConfiguration.class]: Unsatisfied >dependency expressed through method 'typeConverter' parameter 0; nested >exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: >No qualifying bean of type 'org.apache.camel.CamelContext' available: expected >single matching bean but found 2: camel1,camel2
<!-- here we have the 1st CamelContext -->
<camelContext id="camel1" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:one" />
<to uri="mock:result" />
</route>
</camelContext>
<!-- and there we have the 2nd CamelContext -->
<camelContext id="camel2" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:two" />
<to uri="log:two" />
<to uri="mock:result" />
</route>
</camelContext>
My context are being called from Spring boot starter class as follows.
#SpringBootApplication
#ComponentScan(basePackages="com.wm")
#ImportResource("classpath:META-INF/spring/spring-context.xml")
public class ExtAuthServiceAppStarter {
public static void main(String[] args) {
SpringApplication.run(ExtAuthServiceAppStarter.class, args);
}
}
Any suggestions ?
Yes Spring Boot is not an application server to host N+ applications in the same JVM.
Camel on Spring Boot is optimized and adhered to run one CamelContext only.
Right, you can't have multiple Camel Context.
One option to consider, having routes you want to include inside a Route Context instead of a Camel Context. A Route Context is like a subset of a Camel Context. Then you reference the Route Contexts you want to import and Camel will add them to the context.
Reference : https://tomd.xyz/multiple-camel-contexts/
I think you can do that : you have to specify the context in ProducerTemplate tag named #Produce like this :
#Produce(uri = "direct:JMS:export:JMS", context = "camel1")
ProducerTemplate exportProducer
I am currently studying Spring DI.
But I have not been able to run the project due to some error.
Below is a list of errors.
Exception in thread "main"
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
at org.springframework.context.support.GenericXmlApplicationContext.load(GenericXmlApplicationContext.java:124)
at org.springframework.context.support.GenericXmlApplicationContext.<init>(GenericXmlApplicationContext.java:69)
at Spring_DI.MainClass.main(MainClass.java:15)
Caused by: java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
The following is the contents of applicationContext.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.xsd">
<bean id="cats" class="Spring_DI.Cats" />
<!-- "Spring_DI.MyCats"클래스를 myCats라는 id를 지정해서 객체(bean)을 생성 -->
<bean id="myCats" class="Spring_DI.MyCats">
<!-- Spring_DI.Cats.MyCats라는 클래스에 있는 필드들의 값을 설정해줌 -->
<property name="cats"><!-- 첫번째 property(필드) -->
<ref bean="cats"/><!-- 이 property는 위에서 생성한 bean(객체)인 cats를 참조한다. -->
</property>
<property name="firstCatName" value="순덕" /><!-- MyCats의 필드의 이름과 값을 설정 -->
<property name="secondCatName" value="나비" />
<property name="firstCatAge" value="1" />
<property name="secondCatAhttps://stackoverflow.com/jobs?med=site-ui&ref=jobs-tabge" value="2" />
</bean>
</beans>
Here is the contents of the java file.
package Spring_DI;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class MainClass {
public static void main(String[] args) {
//bean을 설정한 xml파일이 있는 위치 지정
String configLocation = "classpath:applicationContext.xml";
//지정한 위치를 참고하여 설정파일을 얻어옴
AbstractApplicationContext ctx =
new GenericXmlApplicationContext(configLocation);
//설정파일에서 bean을 가져옴
//getBean()를 이용해서 MyCats타입에서 myCats를 얻어와서 객체를 생성
// = 방법1 예제처럼 직접 생성이 아닌 외부에서 얻어옴(주입을 시켜줌)
MyCats myCat = ctx.getBean("myCats",MyCats.class);
//호출
myCat.catsNameInfo();
myCat.catsAgeInfo();
}
}
The following is the project structure.
enter image description here
How can I handle the above error?
And why does the above error occur?
Please let me know how to fix the problem.
As per the screenshot, your project is maven project. So the resources(any other files than source files) should be placed in src/main/resources.When Maven build your project, it expects to find only Java source files under src/main/java, and ignores all the other files.
I'm working on a Spring web app, and need to use a Scheduled method that runs in background every certain time, so I created a class "ScheduleDemo", a properties file "schedule.properties" which is placed inside my application, and also added several lines to my applicationContext.xml, and everything is OK.
Now there should be a change that I need to move the schedule.properties file to outside my application, and then I made some changes for my applicationContext.xml, but found the scheduled method cannot run, below is my code, is there any person can provide solutions?
ScheduleDemo.java
#Configuration
#PropertySource("classpath:schedule.properties")
#EnableScheduling
#EnableAsync
Public class ScheduleDemo{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Scheduled(cron="${email.schedule}")
public void doSomething() {
logger.info("Test if it is Okay");
}
}`
schedule.properties
email.schedule = 0 0 8 ? * WED
applicationContext.xml
<task:executor id="executor" pool-size="5" />
<task:scheduler id="scheduler" pool-size="10" />
<task:annotation-driven executor="executor" scheduler="scheduler" />
Then when I moved the schedule.properties file outside my application, I made below changes to applicationContext.xml, I tried "file" or "classpath" to point to external schedule.properties file, but not successfully.
Updated applicationContext.xml
<task:executor id="executor" pool-size="5" />
<task:scheduler id="scheduler" pool-size="10" />
<task:annotation-driven executor="executor" scheduler="scheduler" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:${app.config.location}/schedule.properties</value>
</property>
</bean>`
Trying to run the sample spring-integration mqtt project from web.
I have imported the mqtt-context in root context. After the war is deployed I am running the RunMqtt.java file. But getting the following issue. If running in standalone mode , the same file does not give any issue.
Stack Trace
Creating instance of bean 'startCaseAdapter'
16:50:54.147 DEBUG [main][org.springframework.beans.BeanUtils] No property editor [org.springframework.integration.mqtt.core.MqttPahoClientFactoryEditor] found for type org.springframework.integration.mqtt.core.MqttPahoClientFactory according to 'Editor' suffix convention
16:50:54.148 TRACE [main][org.springframework.beans.TypeConverterDelegate] Field [topic] isn't an enum value
java.lang.NoSuchFieldException: topic
at java.lang.Class.getField(Class.java:1579)
at org.springframework.beans.TypeConverterDelegate.attemptToConvertStringToEnum(TypeConverterDelegate.java:336)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:257)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:107)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:64)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:47)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:706)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1133)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1036)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
at com.iux.ieg.test.mqtt.RunMqtt.test(RunMqtt.java:24)
at com.iux.ieg.test.mqtt.RunMqtt.main(RunMqtt.java:46)
16:50:54.150 TRACE [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Ignoring constructor [public org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter(java.lang.String,java.lang.String,org.springframework.integration.mqtt.core.MqttPahoClientFactory,java.lang.String[])] of bean 'startCaseAdapter': org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'startCaseAdapter': Unsatisfied dependency expressed through constructor argument with index 2 of type [org.springframework.integration.mqtt.core.MqttPahoClientFactory]: Could not convert constructor argument value of type [java.lang.String] to required type [org.springframework.integration.mqtt.core.MqttPahoClientFactory]: Failed to convert value of type 'java.lang.String' to required type 'org.springframework.integration.mqtt.core.MqttPahoClientFactory'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.integration.mqtt.core.MqttPahoClientFactory]: no matching editors or conversion strategy found
16:50:54.150 TRACE [main][org.springframework.beans.TypeConverterDelegate] Converting String to [class [Ljava.lang.String;] using property editor [org.springframework.beans.propertyeditors.StringArrayPropertyEditor#821075]
16:50:54.150 TRACE [main][org.springframework.beans.TypeConverterDelegate] Field [clientId] isn't an enum value
java.lang.NoSuchFieldException: clientId
at java.lang.Class.getField(Class.java:1579)
at org.springframework.beans.TypeConverterDelegate.attemptToConvertStringToEnum(TypeConverterDelegate.java:336)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:257)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:107)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:64)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:47)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:706)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1133)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1036)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
at com.iux.ieg.test.mqtt.RunMqtt.test(RunMqtt.java:24)
at com.iux.ieg.test.mqtt.RunMqtt.main(RunMqtt.java:46)
Configuration
Web-application-config.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: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">
<!-- This file will be the root context file for web app. All other context
will be imported here -->
<!-- Security context . Now the spring security with basic authentication
implemented. OAuth2 will be implemented -->
<import resource="security-config.xml" />
<!-- rest service call context -->
<import
resource="classpath:META-INF/spring/integration/rest/applicationContext-http-int.xml" />
<!-- Sftp context -->
<import
resource="classpath:META-INF/spring/integration/sftp/SftpInboundReceive-context.xml" />
<import
resource="classpath:META-INF/spring/integration/sftp/SftpOutboundTransfer-poll.xml" />
<!-- mqtt context -->
<import resource="classpath:META-INF/spring/integration/mqtt/mqtt-context.xml" />
<!-- Mail Context -->
<import
resource="classpath:META-INF/spring/integration/mail/mail-imap-idle-config.xml" />
<import
resource="classpath:META-INF/spring/integration/mail/mail-pop3-config.xml" />
<!--Component scan base package -->
<context:component-scan base-package="com.iux.ieg" />
<!-- All the property configuration moved to parent context file to solve
the propert not found exception -->
<!-- <context:property-placeholder order="1" location="classpath:/sftpuser.properties,
classpath:/sftpfile.properties,classpath:/resthttp.properties" ignore-unresolvable="true"/> -->
<context:property-placeholder order="0"
location="classpath:/sftpfile.properties" ignore-unresolvable="true" />
<context:property-placeholder order="1"
location="classpath:/sftpuser.properties" ignore-unresolvable="true" />
<context:property-placeholder order="2"
location="classpath:/resthttp.properties" ignore-unresolvable="true" />
<context:property-placeholder order="3"
location="classpath:/mqtt.properties" ignore-unresolvable="true" />
<context:property-placeholder order="4"
location="classpath:/mail.properties" />
</beans>
mqtt-context.xml
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/integration/mqtt http://www.springframework.org/schema/integration/mqtt/spring-integration-mqtt-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:property-placeholder
location="classpath:/mqtt.properties" ignore-unresolvable="true" />
<!-- intercept and log every message -->
<int:logging-channel-adapter id="logger"
level="ERROR" />
<int:wire-tap channel="logger" />
<!-- Mark the auto-startup="true" for starting MqttPahoMessageDrivenChannelAdapter from configuration -->
<int-mqtt:message-driven-channel-adapter
id="startCaseAdapter" client-id="clientId" url="${mqtt.brokerurl}"
topics="topic" channel="startCase" auto-startup="true" />
<int:channel id="startCase" />
<int:service-activator id="startCaseService"
input-channel="startCase" ref="mqttCaseService" method="startCase" />
<bean id="mqttCaseService" class="com.iux.ieg.mqtt.MqttCaseService" />
MqttCaseService.java
import org.apache.log4j.Logger;
public class MqttCaseService {
private static Logger logger = Logger.getLogger(MqttCaseService.class);
public void startCase(String message){
logger.debug(message);
}
}
RunMqtt.java
public class RunMqtt {
private static Logger logger = Logger.getLogger(RunMqtt.class);
//#Test
public void test() throws MqttException{
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("/META-INF/spring/integration/mqtt/mqtt-context.xml");
logger.debug(context);
//MqttPahoMessageDrivenChannelAdapter startCaseAdapter = (MqttPahoMessageDrivenChannelAdapter)context.getBean("startCaseAdapter");
//Uncomment to stop the adapter manually from program
//startCaseAdapter.start();
//DefaultMqttPahoClientFactory mqttClient = (DefaultMqttPahoClientFactory)ac.getBean("clientFactory");
DefaultMqttPahoClientFactory mqttClient = new DefaultMqttPahoClientFactory();
MqttClient mclient = mqttClient.getClientInstance("tcp://*messagebrokerurl*:1883", "JavaSample");
String data = "This is what I am sending in 2nd attempt";
MqttMessage mm = new MqttMessage(data.getBytes());
mm.setQos(1);
mclient.connect();
mclient.publish("topic",mm);
mclient.disconnect();
//Uncomment to stop the adapter manually from program
//startCaseAdapter.stop();
}
public static void main(String[] args) {
try {
new RunMqtt().test();
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
the sample spring-integration mqtt project
Which sample?
Please show your configuration.
EDIT:
It looks like Spring is having trouble determining which constructor to use.
Try adding
<bean id="clientFactory" class="org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory" />
and add client-factory="clientFactory" to the message-driven adapter.