IBM MQ 消费者应用程序无法使用 TextMessage(JMS CMQ 1049:字符集 '1208(UTF-8) 不可映射操作:报告)

IBMMQ consumer application unable to consume 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

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


编辑: 根据@MoragHughson 的要求,我有 运行 amqsbcg,这里是其中一条消息的详细信息:

 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 应该可以正常工作?

所以,你有一个有趣的问题,我以前也遇到过这个问题。

这与《老友记》中的乔治·科斯坦萨所说的相反:“是我不是你”。在你的情况下,它是发件人而不是你。

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 层将尝试将其从 CCSID 1208 转换为 JVM 的 CCSID。问题来自您的消息中包含非字母数字数据这一事实。前 12 个字节中有很多二进制零。

您有 2 个选择:

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

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

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

对未来 MQ 的说明 developers/programmers: 如果您的消息有效负载包含非字母数字数据,则 永远不会 将消息的 MQMD 格式字段设置为“MQSTR”。