Spring Boot JMS No JmsTemplate bean available - spring-boot

I'm trying to send a message with JMS from my application.
I add in my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</dependency>
The spring getting started say
JmsTemplate and ConnectionFactory are created automatically by Spring Boot. In this case, the ActiveMQ broker runs embedded.
and in my batch writer
#Autowired
JmsTemplate jmsTemplate,
void writer(List<String> items) {
jmsTemplate.convertAndSend(items);
}
But the bean JmsTemplate is not found
No qualifying bean of type 'org.springframework.jms.core.JmsTemplate' available: expected at least 1 bean which qualifies as autowire candidate
I tried to add an message converter in the #configuration
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
I tried to add the #EnableJMS (even if it's just for listener...)
But it dosen't work...
I don't understand why, on tutorials it looks like easy...

To work we need to create a jmsTemplate bean
#Bean
public ConnectionFactory getConnectionFactory() {
TibjmsConnectionFactory connectionFactory = new TibjmsConnectionFactory(urlBrocker);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(getConnectionFactory());
template.setPubSubDomain(false); // false for a Queue, true for a Topic
return template;
}

Related

Spring boot 3 and JMS configuration for Amazon SQS

The latest spring boot (i.e. 3.0.1) uses Spring JMS 6.0.3. And the latest Spring JMS that comes with the latest spring boot for ConnectionFactory uses jakarta.jms.ConnectionFactory, while the older JMS was using javax.jms.ConnectionFactory. This was my bean setup and configuration before:
#Configuration
#EnableJms
class JmsConfiguration {
#Autowired
private lateinit var sqsClient: SqsClient
#Bean
fun sqsConnectionFactory(): SQSConnectionFactory =
SQSConnectionFactory(ProviderConfiguration(), sqsClient)
#Bean
fun jmsListenerContainerFactory(): DefaultJmsListenerContainerFactory {
val factory = DefaultJmsListenerContainerFactory()
factory.setConnectionFactory(sqsConnectionFactory())
factory.setDestinationResolver(DynamicDestinationResolver())
factory.setSessionAcknowledgeMode(CLIENT_ACKNOWLEDGE)
return factory
}
#Bean
fun jmsTemplate(): JmsTemplate = JmsTemplate(sqsConnectionFactory())
}
However with the latest Spring boot, I cannot use SQSConnectionFactory, because it hasn't implemented its code based on jakarta rather javax.
Here are my SQS dependencies used:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sqs</artifactId>
<version>2.19.19</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>amazon-sqs-java-messaging-lib</artifactId>
<version>2.0.3</version>
</dependency>
So now I cannot set the connection factory.setConnectionFactory(sqsConnectionFactory()), because it complains sqsConnectionFactory() is not type of jakarta ConnectionFactory. Is there any solution?

intellij show “Could not autowire. No beans of 'JavaMailSender' type found.” while code still run correctly

I'm trying to autowire JavaMailSender
#Autowired
private JavaMailSender javaMailSender;
I have add these to pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
and these to application properties:
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=xxx
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
and the project run correctly (i successed send a mail). but intellij show error on javaMailSender variable. and when i hover my mouse to the error it show
"Could not autowire. No beans of 'JavaMailSender' type found."
How can I fix this error?
You need to create a bean for Javamailsender. If my guess is right, you have a spring security in your dependencies.
You can do it like this:
#Configuration
public class MailConfiguration {
#Bean
public JavaMailSender getJavaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(587);
mailSender.setUsername("my#gmail.com");
mailSender.setPassword("mypassword");
Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
return mailSender;
}
}

Spring Reactive kafka Receiver always overrides bootstrap server to localhost

I am trying to write Spring boot applications for a Reactive Kafka consumer using #EnableKafka and #KafkaListener annotations.
i have configured my kafka brokers are on different machine. when i give bootstrap-server to advertised host of kafka brokers, it is always overriding advertised host ip addresses to localhost. below are my code.
pom.xml file:-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.kafka</groupId>
<artifactId>reactor-kafka</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
config:-
#Configuration
#EnableKafka
public class AppConfig {
#Bean
Map consumerProps() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.12.12.24:9092,192.14.14.28:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "example-group");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
return props;
}
#Bean
ReceiverOptions receiverOptions() {
ReceiverOptions receiverOptions = ReceiverOptions.create(consumerProps()).subscription(Arrays.asList("hellochange"));
return receiverOptions;
}
#Bean
public KafkaReceiver kafkaReceiver() {
return KafkaReceiver.create(receiverOptions());
}
}
Consumer:-
#Service
public class ChangeListener {
#Autowired
KafkaReceiver kafkaReceiver;
#KafkaListener(topics="hellochange",groupId="example-group")
public void receiver() {
kafkaReceiver.receive().subscribe(System.out::println);
}
}
Console:-
auto.commit.interval.ms = 5000
auto.offset.reset = latest
bootstrap.servers = [localhost:9092]
check.crcs = true
client.id =
connections.max.idle.ms = 540000
enable.auto.commit = true
2018-06-07 19:59:17.640 WARN 23536 --- [ntainer#0-0-C-1] org.apache.kafka.clients.NetworkClient : [Consumer clientId=consumer-1, groupId=example-group] Connection to node -1 could not be established. Broker may not be available.
I have validated without spring configurations in a simple consumer and non-reactive Spring kafka, for both, it is working fine. only Reactor kafka with EnableKafka and KafkaListener annotations i am getting this problem.
am i missing something/ doing wrong here ?
can we use EnableKafka and KafkaListener annotations with Reactor Kafka in Spring boot?
P.S. i understood, #EnableKafka and #KafkaListener are not reactive, if i remove spring-kafka from pom.xml, both the annotations are not available.
Like #EnableKafka and #KafkaListener for non-reactive kafka, is there any annotations are available to configure reactive kafka consumer with Spring boot application?
You cannot use KafkaListener annotations with Reactor Kafka; #KafkaListener is not reactive.

Spring Boot client to connect to existing JBoss EAP7 ActiveMQ

I've been searching the web but I cannot find an example on how to connect to ActiveMQ on JBoss (up and running) with a Spring-Boot client.
There'se a lot of tutorials from Spring but using an embedded Broker.
Any pointers would be great!
Thanks in advance,
ML
With the info provided, I've got this:
#Configuration
#SpringBootApplication
#EnableJms
public class Application {
#Bean
ActiveMQConnectionFactory activeMQConnectionFactory() {
final String host = "http://127.0.0.1:8080";
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(host);
factory.setUserName("user");
factory.setPassword("pwd");
factory.setTrustAllPackages(true);
return factory;
}
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the
// message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
#Bean // Serialize message content to json using TextMessage
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
public static void main(String[] args) {
// Launch the application
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
// Send a message with a POJO - the template reuse the message converter
System.out.println("Sending an email message.");
jmsTemplate.convertAndSend("TestQ", new Email("info#example.com", "Hello"));
}
}
my dependencies in pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-optional</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
But I've got this exception:
2017-06-01 17:55:54.176 INFO 2053 --- [ main] hello.Application : Started Application in 2.02 seconds (JVM running for 5.215)
Sending an email message.
[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:527)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:487)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:570)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:658)
at hello.Application.main(Application.java:69)
... 6 more
Caused by: javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:333)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:346)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:304)
at org.apache.activemq.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:244)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:180)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
... 9 more
Caused by: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=127.0.0.1}
at org.apache.activemq.transport.TransportFactory.doConnect(TransportFactory.java:126)
at org.apache.activemq.transport.TransportFactory.connect(TransportFactory.java:65)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:331)
... 14 more
I don't know what is this:
Caused by: java.lang.IllegalArgumentException: Invalid connect
parameters: {wireFormat.host=127.0.0.1}
thanks
For configuration, but change the broker url to your external ActiveMQ server: see http://activemq.apache.org/uri-protocols.html for different protocols (e.g. tcp). You may also need to include a user and password.
I started with this tutorial https://spring.io/guides/gs/messaging-jms/ and made my own edits to get it to work the way I wanted with ActiveMQ, you can also look here for other options: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html. There are a few different ways to do this in Spring.
Also included the factory bean as well. From here, I use #JmsListener annotation to listen for messages and jmstemplate to post messages.
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
#Configuration
#EnableJms
public class JMSConfiguration {
private static final Logger logger = LoggerFactory.getLogger(JMSConfiguration.class);
#Bean ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory factory =
new ActiveMQConnectionFactory("tcp://somehost:61616");
factory.setTrustAllPackages(true);
return factory;
}
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the
// message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
}
Dependencies: spring-boot-starter-activemq
Spring version: 1.4.3.RELEASE

SpringBoot with Quartz and Tomcat datasource: Driver's Blob representation is of an unsupported type: oracle.sql.BLOB

I am using SpringBoot 1.4.5 and quartz for scheduling with a DataSource configured in Tomcat's context.xml which is injected as a bean via JndiDataSource for connecting to a Oracle 10g DB.
Here are the relevant dependencies, including the Oracle driver, I am using the dependency management provided by SpringBoot:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>oracle-ojdbc7</artifactId>
<version>12.1.0-2</version>
</dependency>
This is the DataSource configured in Tomcat in context.xml (the placeholder properties are defined in catalina.properties) :
<Resource name="${tomcat.dbpool.ups.quartz.resourcename}" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="${tomcat.dbpool.ups.quartz.connectionurl}"
username="${tomcat.dbpool.ups.quartz.username}"
password="${tomcat.dbpool.ups.quartz.password}"
maxTotal="${tomcat.dbpool.ups.quartz.maxTotal}"
maxIdle="${tomcat.dbpool.ups.quartz.maxIdle}"
minIdle="${tomcat.dbpool.ups.quartz.minIdle}"
maxWaitMillis="${tomcat.dbpool.ups.quartz.maxWaitMillis}"
validationQueryTimeout="${tomcat.dbpool.ups.quartz.validationQueryTimeout}"
testWhileIdle="true"
removeAbandonedOnMaintenance="true"
timeBetweenEvictionRunsMillis="${tomcat.dbpool.ups.quartz.timeBetweenEvictionRunsMillis}"
minEvictableIdleTimeMillis="${tomcat.dbpool.ups.quartz.minEvictableIdleTimeMillis}"
/>
The datasource bean configuration and quartz necessary beans:
#Bean
public JobFactory jobFactory(final ApplicationContext applicationContext) {
final AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(#Qualifier("quartzDataSource") final DataSource quartzDS,
final JobFactory jobFactory,
#Qualifier("loansAppTrigger") final Trigger jobTrigger) throws IOException {
final SchedulerFactoryBean factory = new SchedulerFactoryBean();
// this allows to update triggers in DB when updating settings in config file:
factory.setOverwriteExistingJobs(true);
factory.setDataSource(quartzDS);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.setTriggers(jobTrigger);
return factory;
}
#Bean(name = "quartzDataSource")
#Profile("!local")
public DataSource jndiDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/QUARTZ");
return dataSource;
}
#Bean
public Properties quartzProperties() throws IOException {
final PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
#Bean
public JobDetailFactoryBean checkUnconfirmedApplicationsJobDetail() {
return createJobDetail(CheckUnconfirmedApplicationsJob.class);
}
#Bean(name = "loansAppTrigger")
public SimpleTriggerFactoryBean unconfirmedLoansApplicationsTrigger(
#Qualifier("checkUnconfirmedApplicationsJobDetail") final JobDetail jobDetail,
#Value("${ups.loan.check.pending.apps.frequency}") final long frequency) {
return createTrigger(jobDetail, frequency);
}
private static JobDetailFactoryBean createJobDetail(final Class jobClass) {
final JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
// job has to be durable to be stored in DB:
factoryBean.setDurability(true);
return factoryBean;
}
private static SimpleTriggerFactoryBean createTrigger(final JobDetail jobDetail, final long pollFrequencyMs) {
final SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(0L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
// in case of misfire, ignore all missed triggers and continue :
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
return factoryBean;
}
And the following properties in quartz.properties file:
org.quartz.scheduler.instanceName=scheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
When I deploy this on Tomcat 8 I get the following error :
org.quartz.JobPersistenceException: Couldn't store job: Driver's Blob representation is of an usupported type: oracle.sql.BLOB
In Tomcat's lib folder I have the oracle-ojdbc7-12.1.0-2.jar driver.
Can you please check if you have any duplicate oracle-ojdbc JAR files present? The JAR should be in only one location: either in WEB-INF/lib or under tomcat/lib

Resources