Closed mlakshminara closed 1 year ago
The above error occurs when you include spring-boot-starter-activemq dependency in your POM, even without creating JMS listener.
There are no jms samples so no guarantees it will work without extra configuration. so attempting to collect any missing config with the agent is the right idea. I am most surprised to see the agent crash it. I would recommend trying with the Java 11 20.3 GraalVM rather than Java8. I will need to try a simpler sample, maybe https://spring.io/guides/gs/messaging-jms/ is a good starting point. Hope it represents your use case.
Hi, I was able to start the agent with Java 11 & GraalVM v20.3 without error and see attached reflect-config.txt file for the list of java classes to add in reflect-config.json reflect-config.txt
During application load, I also found that @Autowired and @Value annotations doesn't work in @Configuration class. So if you have to read properties you need to implement EnvironmentAware. Sample JmsTemplate config is as given below
@Configuration
public class JmsTemplateConfig implements EnvironmentAware {
private Environment env;
@Bean
public JmsTemplate jmsTemplate() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
// create an Jackson Json Mapping Converter
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setObjectMapper(objectMapper);
//create an instance of ActiveMQ connection factory
String brokerUrl = env.getProperty("broker-url");
log.info("The ActiveMQ Url provided is: {}", brokerUrl);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl);
// create instance of JmsTemplate
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(connectionFactory);
jmsTemplate.setMessageConverter(converter);
jmsTemplate.setExplicitQosEnabled(true);
jmsTemplate.setDeliveryMode(2);
return jmsTemplate;
}
}
I also encountered errors in MappingJackson2MessageConverter and you need to have reflection for Jackson API's. Finally was able to start the application.
While publishing message to ActiveMQ at runtime, I have configured to convert POJO to JSON object using MappingJackson2MessageConverter and right now am encountering com.fasterxml.jackson.databind.exc.InvalidDefinitionException error when I invoke jmsTemplate.convertAndSend method during runtime. A sample publisher is as given below:
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void publish(String eventCode, String destinationName, Event payload) {
jmsTemplate.convertAndSend(destinationName, event, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws JMSException
{
message.setJMSCorrelationID(event.getId());
message.setStringProperty("event_code", event.getCode());
return message;
}
});
log.info ("Successfully published message with correlation id: {}", event.getId());
}
The error stack-trace is
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.bestminds.petclinic.domain.Event and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516)
at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1217)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1059)
at org.springframework.jms.support.converter.MappingJackson2MessageConverter.mapToTextMessage(MappingJackson2MessageConverter.java:279)
at org.springframework.jms.support.converter.MappingJackson2MessageConverter.toMessage(MappingJackson2MessageConverter.java:184)
at org.springframework.jms.core.JmsTemplate.lambda$convertAndSend$7(JmsTemplate.java:692)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:604)
at org.springframework.jms.core.JmsTemplate.lambda$send$3(JmsTemplate.java:586)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:504)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:584)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:691)
at com.bestminds.petclinic.publisher.ActiveMqPublisher.publish(ActiveMqPublisher.java:49)
at java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy347.publish(Unknown Source)
at com.bestminds.petclinic.service.OwnerServiceImpl.save(OwnerServiceImpl.java:47)
Any clue to solve this error ?
I was able to get the publishing working, solved the above error by adding the POJO class which one will pass as an argument to jmsTemplate.convertAndSend method in reflect-config.json
Micronaut has @Introspected annotation. Do Spring is planning to introduce to generate introspection classes at compile time
The reflect-config configuration also works for consumers. sample DMLC configuration and Listener is as given below:
@Configuration
public class DmlcConfig implements EnvironmentAware {
private Environment env;
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory()
{
//create an instance of ActiveMQ connection factory
String brokerUrl = env.getProperty("broker-url");
log.info("The ActiveMQ Url provided for DMLC configuration is: {}", brokerUrl);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl);
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency("1-20");
factory.setSessionTransacted(true);
factory.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
return factory;
}
@Override
public void setEnvironment(Environment environment) {
this.env = environment;
}
}
Sample JMS Listener: Need to add the Java Class in reflect-config.json
@Component
public class SampleListener {
@JmsListener(destination = "test_queue")
public void onMessage (final Message jsonMessage) {
try
{
if (jsonMessage instanceof TextMessage)
{
// Retrieves the message from ActiveMQ
// Read the data attribute in event as Map of key/value pairs
String messageData = ((TextMessage)jsonMessage).getText();
// Reads the messages from ActiveMQ
final Event event = objectMapper.readValue(messageData, Event.class);
log.info ("The event object obtained is: {}", event.toString());
}
}
catch (final JMSException exception) {
throw new RuntimeException (exception);
}
}
}
@mlakshminara You can use native hints if you need to add native configuration is a Spring way.
I'ma lso trying to have JmsTemplate
work in a native image.
Here are the hints I added to now:
@NativeHint(
jdkProxies = {
@JdkProxyHint(types = { org.springframework.jms.annotation.JmsListeners.class }),
})
@TypeHint(types = { org.apache.activemq.ActiveMQConnectionFactory.class })
And here is the issue I'm stuck on:
"org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not create Transport. Reason: java.io.IOException: Transport scheme NOT recognized: [tcp]"
Spring Native is now superseded by Spring Boot 3 official native support, see the related reference documentation for more details.
As a consequence, I am closing this issue, and recommend trying your use case with latest Spring Boot 3 version. If you still experience the issue reported here, please open an issue directly on the related Spring project (Spring Framework, Data, Security, Boot, Cloud, etc.) with a reproducer.
Thanks for your contribution on the experimental Spring Native project, we hope you will enjoy the official native support introduced by Spring Boot 3.
I took the Spring Pet Clinic JPA sample application and added enhancement to publish/subscribe JMS messages to ActiveMQ. I have used native-image-maven-plugin to build the native image. Image construction works properly and when I start the application, application crashes and gives the below error.
In fact I tried analysing using agent but it crashed too. I wanted to know do we have support for JMS in native image.
I tried analysing using agent but that also crashed as given below: