'DefaultJmsHeaderMapper - failed to map Message header 'timestamp' to JMS property
I have a problem with the 'timestamp' header that comes from the JMSMessageProperties class, or so it seems to me, and it causes the following error
[WARN ] [2022-04-06 14:49:03,758] [voryouDuplicateCheck.container-1] DefaultJmsHeaderMapper - failed to map Message header 'timestamp' to JMS property
javax.jms.MessageNotWriteableException: Message properties are read-only
at org.apache.activemq.command.ActiveMQMessage.checkReadOnlyProperties(ActiveMQMessage.java:740) ~[activemq-client-5.15.0.jar:5.15.0]
at org.apache.activemq.command.ActiveMQMessage.setObjectProperty(ActiveMQMessage.java:494) ~[activemq-client-5.15.0.jar:5.15.0]
at org.apache.activemq.command.ActiveMQMessage.setObjectProperty(ActiveMQMessage.java:488) ~[activemq-client-5.15.0.jar:5.15.0]
at org.springframework.integration.jms.DefaultJmsHeaderMapper.fromHeaders(DefaultJmsHeaderMapper.java:152) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.jms.DefaultJmsHeaderMapper.fromHeaders(DefaultJmsHeaderMapper.java:57) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.jms.JmsSendingMessageHandler$HeaderMappingMessagePostProcessor.postProcessMessage(JmsSendingMessageHandler.java:167) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.jms.core.JmsTemplate$7.createMessage(JmsTemplate.java:686) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:593) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:562) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:484) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:559) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:682) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.integration.jms.JmsSendingMessageHandler.send(JmsSendingMessageHandler.java:143) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.jms.JmsSendingMessageHandler.handleMessageInternal(JmsSendingMessageHandler.java:116) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) [spring-messaging-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:150) [spring-messaging-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:45) [spring-messaging-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.messaging.core.AbstractMessagingTemplate.sendAndReceive(AbstractMessagingTemplate.java:42) [spring-messaging-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:97) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:459) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:426) [spring-integration-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener$GatewayDelegate.sendAndReceiveMessage(ChannelPublishingJmsMessageListener.java:512) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.integration.jms.ChannelPublishingJmsMessageListener.onMessage(ChannelPublishingJmsMessageListener.java:344) [spring-integration-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:317) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:255) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1166) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055) [spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
I know this is due to the checkReadOnly variable in ActiveMQMessage class and the following methods are responsible for this
@Override
public void setObjectProperty(String name, Object value) throws JMSException {
setObjectProperty(name, value, true);
}
public void setObjectProperty(String name, Object value, boolean checkReadOnly) throws JMSException {
if (checkReadOnly) {
checkReadOnlyProperties();
}
if (name == null || name.equals("")) {
throw new IllegalArgumentException("Property name cannot be empty or null");
}
if (value instanceof UTF8Buffer) {
value = value.toString();
}
checkValidObject(value);
value = convertScheduled(name, value);
PropertySetter setter = JMS_PROPERTY_SETERS.get(name);
if (setter != null && value != null) {
setter.set(this, value);
} else {
try {
this.setProperty(name, value);
} catch (IOException e) {
throw JMSExceptionSupport.create(e);
}
}
}
private void checkReadOnlyProperties() throws MessageNotWriteableException {
if (readOnlyProperties) {
throw new MessageNotWriteableException("Message properties are read-only");
}
}
and the DefaultJmsHeaderMapper class ich catching the Exception and logging this as WARN
@Override
public void fromHeaders(MessageHeaders headers, javax.jms.Message jmsMessage) {
try {
Object jmsCorrelationId = headers.get(JmsHeaders.CORRELATION_ID);
if (jmsCorrelationId instanceof Number) {
jmsCorrelationId = jmsCorrelationId.toString();
}
if (jmsCorrelationId instanceof String) {
try {
jmsMessage.setJMSCorrelationID((String) jmsCorrelationId);
}
catch (Exception e) {
this.logger.info("failed to set JMSCorrelationID, skipping", e);
}
}
Object jmsReplyTo = headers.get(JmsHeaders.REPLY_TO);
if (jmsReplyTo instanceof Destination) {
try {
jmsMessage.setJMSReplyTo((Destination) jmsReplyTo);
}
catch (Exception e) {
this.logger.info("failed to set JMSReplyTo, skipping", e);
}
}
Object jmsType = headers.get(JmsHeaders.TYPE);
if (jmsType instanceof String) {
try {
jmsMessage.setJMSType((String) jmsType);
}
catch (Exception e) {
this.logger.info("failed to set JMSType, skipping", e);
}
}
for (Entry<String, Object> entry : headers.entrySet()) {
String headerName = entry.getKey();
if (StringUtils.hasText(headerName) && !headerName.startsWith(JmsHeaders.PREFIX)
&& jmsMessage.getObjectProperty(headerName) == null) {
Object value = entry.getValue();
if (value != null) {
if (SUPPORTED_PROPERTY_TYPES.contains(value.getClass())) {
try {
String propertyName = this.fromHeaderName(headerName);
jmsMessage.setObjectProperty(propertyName, value);
}
catch (Exception e) {
if (headerName.startsWith("JMSX")
|| headerName.equals(IntegrationMessageHeaderAccessor.PRIORITY)) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("skipping reserved header, it cannot be set by client: "
+ headerName);
}
}
else if (this.logger.isWarnEnabled()) {
this.logger.warn("failed to map Message header '" + headerName + "' to JMS property", e); // **<-- this part**
}
}
}
else if (IntegrationMessageHeaderAccessor.CORRELATION_ID.equals(headerName)) {
String propertyName = fromHeaderName(headerName);
jmsMessage.setObjectProperty(propertyName, value.toString());
}
}
}
}
}
catch (Exception e) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("error occurred while mapping from MessageHeaders to JMS properties", e);
}
}
}
I know this is just a warning but we want to keep logs clean so the idea is to not log this specific WARN or try to not pass the header.
I've create a custom mapper based on DefaultJmsHeaderMapper and use it but as u can see in the starcktrace the default one is still in use.
Here the configuration in XML file
<bean id="voryouDuplicateCheckQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="voryouDuplicateCheck${jms.queue.postfix}" />
</bean>
<bean id="voryouDuplicateCheckCustomJmsHeaderMapper" class="com.example.ws.impl.voryou.CustomJmsHeaderMapper" >
</bean>
<int-jms:inbound-gateway id="voryouDuplicateCheck"
request-destination="voryouDuplicateCheckQueue"
request-channel="voryouDuplicateCheckChannel"
extract-request-payload="false"
header-mapper="voryouDuplicateCheckCustomJmsHeaderMapper"
auto-startup="true"
/>
<int:channel id="voryouDuplicateCheckChannel">
<int:interceptors>
<int:wire-tap channel="loggingServiceChannel" />
</int:interceptors>
</int:channel>
<int:service-activator id="activatorSasoVoryouDuplicateCheck" input-channel="voryouDuplicateCheckChannel" ref="voryouDuplicateCheckBES"
method="getRequest" output-channel="loggingChannel" />
Have any of you encountered a similar problem and found any solution? The main goal is not to log this type of error.
Solution 1:[1]
First of all, 4.3.x is no longer supported. The last 4.3.x. version was 4.3.24 at the end of 2020.
Second, it is strange that the properties are marked as read-only during message creation.
One way to avoid the log is to set the log level for the header mapper to ERROR.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Gary Russell |
