首页 > 解决方案 > IBMMQ 消费者应用程序无法使用 TextMessage(JMSCMQ1049: The character set '1208(UTF-8) Unmappable Action: REPORT)

问题描述

我有一个消费者应用程序,它使用 IBMMQ 来使用来自队列管理器的消息。我无法控制发布者,只有消费者。这是我的消费者的部分代码:

while(true) {
    message = (TextMessage) queueReceiver.receive(200);
                
    if (message != null) {
             messageFile = messageTypeToListenerMapping.get(type).generateMessageNameAndWriteToDisk(message.getText(), source, saveDirectory);
    } else {
             break;
    }      

此代码工作正常,并且能够将消息作为TextMessage对象检索到我的几乎所有队列(一个队列除外)。当应用程序尝试从此队列中检索消息时,我收到此错误:

2021-10-05 22:12:31.831 DEBUG 30050 --- [nio-8181-exec-8] o.s.web.servlet.DispatcherServlet        : GET "/retrieveAllMessagesFromQueue", parameters={}
2021-10-05 22:12:31.832 DEBUG 30050 --- [nio-8181-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.lang.Integer>>>  ,
2021-10-05 22:12:36.882 DEBUG 30050 --- [nio-8181-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler public Exception.ApiErrorResponse Octopus.controller.OctopusRestController.handleJmsException(javax.jms.JMSException)
2021-10-05 22:12:36.899 DEBUG 30050 --- [nio-8181-exec-8] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2021-10-05 22:12:36.899 DEBUG 30050 --- [nio-8181-exec-8] m.m.a.RequestResponseBodyMethodProcessor : Writing [com.ApiErrorResponse@4be14d5e]
2021-10-05 22:12:36.900 DEBUG 30050 --- [nio-8181-exec-8] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [com.ibm.msg.client.jms.DetailedJMSException: JMSCMQ1049: The character set '1208(UTF-8) Unmappable Action: REPORT, Unmappable Replacement: 63, spaceByte: 32' cannot convert some or all of the string '[B@47412132'
An attempt was made to send or receive string data using a character set not capable of translating the strings content.
Only encode a message using a character set known to be appropriate for the string data being transmitted.]
2021-10-05 22:12:36.901 DEBUG 30050 --- [nio-8181-exec-8] o.s.web.servlet.DispatcherServlet        : Completed 500 INTERNAL_SERVER_ERROR

在做了一些调试后,我发现执行这段代码时出现错误:message.getText()

我相信发布者放入队列的消息可能包含某种应用程序无法处理的特殊字符。因此,我尝试查看是否可以BytesMessage改为使用此特定队列的消息。下面是代码:

BytesMessage byteMessage;

byteMessage = (BytesMessage) queueReceiver.receive(200);
int TEXT_LENGTH = new Long(byteMessage.getBodyLength()).intValue();
byte[] text_bytes = new byte[TEXT_LENGTH];
byteMessage.readBytes(text_bytes, TEXT_LENGTH);
String codePage = byteMessage.getStringProperty(WMQConstants.JMS_IBM_CHARACTER_SET);
String textString = new String(text_bytes, codePage);

     if (textString != null) {
              messageFile = messageTypeToListenerMapping.get(type).generateMessageNameAndWriteToDisk(textString, source, saveDirectory)
     } else {
              break;
     }

但是我遇到了这个错误:

2021-10-27 22:29:34.046 DEBUG 20987 --- [nio-8181-exec-1] o.s.web.servlet.DispatcherServlet        : Failed to complete request: java.lang.ClassCastException: com.ibm.jms.JMSTextMessage cannot be cast to javax.jms.BytesMessage
2021-10-27 22:29:34.053 ERROR 20987 --- [nio-8181-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: com.ibm.jms.JMSTextMessage cannot be cast to javax.jms.BytesMessage] with root cause
java.lang.ClassCastException: com.ibm.jms.JMSTextMessage cannot be cast to javax.jms.BytesMessage

据我了解,消息无法从TextMessageto投射ByteMessage,这也意味着发布者将消息作为TextMessage. 如果发布者以 . 形式发送消息TextMessage,那么为什么我首先会遇到这个问题?我对这一切有点困惑,希望得到一些指导。


编辑:我已amqsbcg按照@MoragHughson 的要求运行,以下是其中一条消息的详细信息:

 MQGET of message number 14861, CompCode:0 Reason:0
****Message descriptor****

  StrucId  : 'MD  '  Version : 2
  Report   : 0  MsgType : 8
  Expiry   : -1  Feedback : 0
  Encoding : 546  CodedCharSetId : 1208
  Format : 'MQSTR   '
  Priority : 0  Persistence : 1
  MsgId : X'414D5120514D2E44303014D5120514D2E443030A0EF121'
  CorrelId : X'000000000000000000000000000000000000000000000000'
  BackoutCount : 0
  ReplyToQ       : '                                                '
  ReplyToQMgr    : 'QM.1010101_4642                                 '
  ** Identity Context
  UserIdentifier : 'user2      '
  AccountingToken :
   X'0A31303030303639333331639333331639333331004568490000000000000006'
  ApplIdentityData : '                                '
  ** Origin Context
  PutApplType    : '6'
  PutApplName    : 'mqm_sender             '
  PutDate  : '00000000'    PutTime  : '00000000'
  ApplOriginData : '    '

  GroupId : X'000000000000000000000000000000000000000000000000'
  MsgSeqNumber   : '1'
  Offset         : '0'
  MsgFlags       : '0'
  OriginalLength : '-1'

****   Message      ****

 length - 64 of 64 bytes

00000000:  0000 0000 B3DC B059 6400 0000 524D 5320           '.....ܰYd...RMS '
00000010:  2052 3235 3139 3435 3734 3437 3030 3030           ' R25194574470000'
00000020:  3120 2020 2020 2020 2020 2020 2020 2032           '1              2'
00000030:  3032 3131 3032 3231 3431 3333 3730 3020           '021102214133700 '



 No more messages
 MQCLOSE


看来 CodedCharSetId 是 1208,这似乎是 UTF-8。如果是这种情况,那么如果我没记错的话,TextMessages 应该可以正常工作吗?

标签: javaencodingutf-8jmsibm-mq

解决方案


所以,你有一个有趣的问题,而我以前也曾走过这条路。

这与《老友记》中的 George Costanza 所说的相反:“是我,不是你”。在您的情况下,它是发件人而不是您。

amqsbcg 转储中有 3 条重要信息:

Encoding : 546  CodedCharSetId : 1208
Format : 'MQSTR   '
00000000:  0000 0000 B3DC B059 6400 0000 524D 5320           '.....?Yd...RMS '

(1) 该消息不是 JMS(又名 MQRFH2)消息,但 JMS/MQ 层会将其转换为应用程序的 JMS 消息。

  • 如果 MQMD 格式字段设置为“MQSTR”,那么 MQ/JMS 层将创建一个 TextMessage。
  • 如果 MQMD 格式字段设置为“”(全为空白),则 MQ/JMS 层将创建一个 BytesMessage。

(2) 由于传入消息的 MQMD 格式字段设置为“MQSTR”,JMS/MQ 层将尝试将其从 1208 的 CCSID 转换为您的 JVM 的 CCSID。问题来自您的消息中包含非字母数字数据这一事实。前 12 个字节中有很多二进制零。

您有 2 个选项:

(1) 要求发件人停止在消息中包含非字母数字数据。

(2) 如果非字母数字数据很重要,则告诉发送方将消息的 MQMD 格式字段设置为“”(全为空白)。然后,当您收到消息时,只需将其转换为 BytesMessage。

很可能一些初级程序员从 StackOverflow 或其他地方复制代码并在不了解代码的作用的情况下使用它。

对未来 MQ 开发人员/程序员的注意事项:如果您的消息负载包含非字母数字数据,则永远不要将消息的 MQMD 格式字段设置为“MQSTR”。


推荐阅读