特殊字符问题:MQ 消息 PUT 错误:java.nio.charset.UnmappableCharacterException

2024-01-08

我有一个设置,其中有 JMS 生产者和 JMS 接收器。发送者应用程序发送如下消息:

source text ⟨е, ё, и, ю, я⟩  abcdefg

JMS 接收器收到消息后,使用纯 IBM MQ API 类将其放入 IBM MQ 队列。

将此消息发送到 MQ 时,我收到以下异常:

INFO  | 2020-09-17 09:45:19 | [main] mimq.MQReceiver (MQReceiver.java:211) - IO Exception Occurred: Input length = 1
java.nio.charset.UnmappableCharacterException: Input length = 1
        at java.nio.charset.CoderResult.throwException(CoderResult.java:282)
        at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:816)
        at com.ibm.mq.jmqi.system.JmqiCodepage.stringToBytes(JmqiCodepage.java:923)
        at com.ibm.mq.MQMessage.writeString(MQMessage.java:2848)
        at com.ibm.mimq.MQReceiver.sendToAnotherQueue(MQReceiver.java:192)
        at com.ibm.mimq.MQReceiver.main(MQReceiver.java:113)

下面是我的MQ PUT code :

public static void sendToLocalQueue(String msg) {
    
    int port = 1414;
    String host = "some-host";
    String channel = "some-channel";
    String manager = "some-QM";
    String user = "user"; 
    String passwd = "passwd";
    String qname = "TEST";
    String qmname = "some-QM";
    
    MQQueueManager qMgr;
    MQQueue inputQ;
    
    try {       
        
        Hashtable<String, String> h = new Hashtable<String, String>();
        h.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
        MQEnvironment.properties = h;
        MQEnvironment.hostname  = host;
        MQEnvironment.port      = port;
        MQEnvironment.channel   = channel;
        
        MQEnvironment.userID    = user;
        MQEnvironment.password  = passwd;
        MQEnvironment.disableTracing();
        MQException.log = null;
        qMgr = new MQQueueManager(manager);
        
        MQMessage m = new MQMessage();      
        m.applicationOriginData = "AMPS";
        m.messageType   = MQC.MQMT_DATAGRAM;
        m.format        = MQC.MQFMT_STRING;
        m.encoding      = MQC.MQENC_NATIVE;
        m.priority      = 4;
        m.persistence   = MQC.MQPER_PERSISTENT;
        m.characterSet  = MQC.MQCCSI_Q_MGR;
        //m.characterSet = 1208;
        m.expiry        =  MQC.MQEI_UNLIMITED;
        m.writeString(msg);
        
        MQPutMessageOptions putOptions = new MQPutMessageOptions();
        putOptions.options = MQC.MQPMO_SYNCPOINT | MQC.MQPMO_FAIL_IF_QUIESCING; 
        
        logger.info("Putting message to LAN MQ (TEST queue)....");          
        qMgr.put(qname, qmname, m, putOptions);
        qMgr.commit();
        
        
    } catch(MQException me) {
        logger.info("Error Code       : "  +me.getErrorCode());
        logger.info("LocalizedMessage : "  +me.getLocalizedMessage());
        logger.info("Message          : "  +me.getMessage());
        logger.info("Reason           : "  +me.getReason());
        me.printStackTrace();
        
    } catch (IOException e) {
        // TODO Auto-generated catch block
        logger.info("IO Exception Occurred       : "  +e.getLocalizedMessage());
        e.printStackTrace();
    }       
}

由于不可映射字符,无法将消息放入队列。编码在队列管理器级别设置为 UTF-8。

但是,当我替换以下行时:m.characterSet = MQC.MQCCSI_Q_MGR;

与行:m.characterSet = 1208;问题已经不存在了。

我的问题是为什么这种转换没有在 MQ 级别完成。我需要检查哪些设置以确保正确转换。我尝试过以下技术,但不起作用:

Setting java parameter as : -Dfile.encoding=UTF-8 

My 环境 :

Server : Linux
MQ : 9.0  or 7.5
Java : 1.8

还要提一下,迁移后相同的设置适用于 7.5,但不适用于 MQ 9.0。我知道通过上面的一行代码更改我可以传递消息。但我想了解 MQ 级别是否遗漏了一些配置。任何建议将不胜感激。

谢谢。

UPDATE

我将消息发送到 MQ 的客户端计算机具有 CCSID :MQMD.CodedCharSetId = 1208

我连接并发送消息的 MQ 服务器具有以下内容:

getDefaultProperty(Object) returns [819(0x333)] Integer
setCCSID(int) setter [819(0x333)]

因此,当我在代码中显式设置 1208 时,它就可以工作。如果不是,转换就会失败。

UPDATE-2

价值MQC.MQCCSI_Q_MGR is Zero正如我在罐子里看到的那样。因此,代码是这样设计的,如果该值为零,它将从 Jar 中获取默认值,该值设置为819。当我打开 MQ 跟踪时我了解到了这一点。代码是这样的:

getDefaultProperty(Object) returns [819(0x333)] Integer
setCCSID(int) setter [819(0x333)]

此代码存在于 jar 内。因此,我们需要显式设置消息的字符集值。就我而言,它是 1208。


这在 MQ v7.5 上起作用而不是在 MQ v9.0 上起作用的原因是,在 IBM MQ v8.0 之前,用于 Java 编码数据的 IBM MQ 类使用java.nio.charset.Charset.encode(CharBuffer)这会导致默认替换格式错误或无法翻译的数据。由于默认characterSet是 819 (ASCII),这将导致您发送的任何无法转换为 ASCII 的字符被透明地替换为默认替换字符,在大多数情况下,这意味着数据被替换为?特点。

在 v8.0 之后,默认行为更改为将此情况报告为错误,并且默认情况下不再替换格式错误或无法翻译的数据。


将字符集设置为 UTF-8 的解决方案是最佳解决方案,因为这会导致发送您想要发送的确切数据。

另一种选择是告诉 MQ 使用先前的行为。


IBM MQ 9.0 知识中心页面描述了新行为以及如何配置 IBM MQ 类 for Java 以使用先前的行为开发应用程序>开发 JMS 和 Java 应用程序>使用适用于 Java 的 IBM MQ 类>适用于 Java 的 IBM MQ 类中的字符串转换 https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.dev.doc/q120590_.htm:

从 IBM® MQ Version 8.0 开始,一些有关以下内容的默认行为 IBM MQ Java™ 类中的字符串转换具有 改变了。

在 IBM MQ 版本 8.0 之前,IBM MQ 类中的字符串转换为 Java 是通过调用 java.nio.charset.Charset.decode(ByteBuffer) 和 Charset.encode(CharBuffer) 方法。

使用这些方法中的任何一个都会导致默认替换( REPLACE)格式错误或无法翻译的数据。

此行为可能会掩盖应用程序中的错误,并导致 翻译数据中出现意外字符,例如 ?。来自 IBM MQ 8.0版本,为了更早、更有效地检测此类问题, IBM MQ Java 类使用 CharsetEncoder 和 CharsetDecoder 直接配置格式错误和不可翻译的处理 数据明确。

从 IBM MQ 版本 8.0 开始,默认行为是报告此类问题 通过抛出合适的 MQException。

...

设置系统默认值 --

从 IBM MQ 版本 8.0 开始,以下两个 Java 系统属性是 可配置有关字符串的默认行为 转换。

com.ibm.mq.cfg.jmqi.UnmappableCharacterAction指定对不可翻译的数据在编码和解码时要采取的操作。 该值可以是 REPORT、REPLACE 或 IGNORE。

com.ibm.mq.cfg.jmqi.UnmappableCharacterReplacement设置或获取当无法映射字符时要应用的替换字节 在编码操作中使用默认的Java替换字符串 在解码操作中。

避免 Java 字符和本机字节之间的混淆 表示,您应该指定 com.ibm.mq.cfg.jmqi.UnmappableCharacterReplacement 作为十进制数 表示本机字符集中的替换字节。

例如,作为本机字节的 ? 的十进制值为 63,如果 本机字符集是基于 ASCII 的,例如 ISO-8859-1,而它是 111(如果本机字符集是 EBCDIC)。


如果您想模仿之前的行为,您可以设置以下系统属性:

-Dcom.ibm.mq.cfg.jmqi.UnmappableCharacterAction=REPLACE
-Dcom.ibm.mq.cfg.jmqi.UnmappableCharacterReplacement=63

您还可以通过编程方式设置它,如下所示:

System.setProperty("com.ibm.mq.cfg.jmqi.UnmappableCharacterAction", "REPLACE");
System.setProperty("com.ibm.mq.cfg.jmqi.UnmappableCharacterReplacement", "63");
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

特殊字符问题:MQ 消息 PUT 错误:java.nio.charset.UnmappableCharacterException 的相关文章

随机推荐

  • Excel 隐藏/显示功能区上除自定义选项卡之外的所有选项卡

    如何使用 VBA 而不是 XML 隐藏和显示所有标准 Excel 功能区选项卡 我不想隐藏整个功能区 正如这里所要求的 VBA 最小化 Excel 中的功能区 https stackoverflow com questions 190195
  • 添加自定义刻度和标签

    我想在 matplotlib 中添加自定义主要刻度和标签 典型用途是在该位置添加标签math pi与标签 pi 我的目标是让其他刻度保持原样 我想保留原始的主要和次要刻度以及之前选择的格式 但带有这个额外的刻度和标签 我已经找到了一种方法
  • 使用 1:n 中的唯一值创建 n × n 矩阵

    我想在 R 中生成一个随机的 n n 矩阵 离散值范围从 1 到 n 棘手的部分是我希望每个值在行和列中都是唯一的 例如 如果n 3矩阵可能如下所示 1 2 3 2 3 1 3 1 2 或者它可能看起来像这样 2 3 1 1 2 3 3 1
  • 我的 git 存储库中的所有这些隐藏('._' 前缀)文件是什么?

    当我在目录上执行 git status 时 它会显示一堆未跟踪的文件 这些文件似乎是重复的 唯一的区别是它们都有一个前缀 例如 我需要添加的未跟踪文件之一是 app assets stylesheets categories css另一个文
  • 如何在 angular2 中显示/隐藏 div 的动态 id

    这里执行了 kpiName 的循环 并且也执行了 subRegion 的内部循环 结果 4 divclass col xs 2 创建并在其中创建两个 div 过滤器类内的可点击 div 其动态 ID 为id filteredTabSubRe
  • 如何从 Pyspark 中的日期列中减去天数列?

    给定以下 PySpark DataFrame df sqlContext createDataFrame 2015 01 15 10 2015 02 15 5 date col days col 如何从日期列中减去天数列 在此示例中 结果列
  • Java 中的 Ruby 解析器

    我正在做的项目是用 Java 和解析器源代码文件编写的 到目前为止的 Java src 现在我也想启用解析 Ruby 代码 因此 我正在寻找一个可以解析 Ruby 源代码的 Java 解析器 到目前为止我唯一能找到的是 Ruby 中的 Ru
  • 从批处理文件运行 python 脚本时出现 ModuleNotFoundError

    我有一个简单的 python 脚本 名为sc py翻译一个词 这是我的代码 python3 from googletrans import Translator import sys translator Translator dest h
  • Excel VBA 创建文件夹、子文件夹和更多子文件夹

    我有一个问题与我在这里看到的其他一些问题非常相似 但它们并没有完全回答我需要的问题 或者当我尝试它们时 它导致了一个我不知道如何解决的错误 只有5级我无法发表评论来提问 在 Excel 中 我有一个用于引用文件夹的命名配置文件的文件 我尝试
  • kerascompute_output_shape不适用于自定义层

    我自定义了一个层 将batch size和第一个维度合并 其他维度不变 但是compute output shape好像没有效果 导致后面的层无法得到准确的形状信息 从而产生错误 如何使compute output shape工作 impo
  • C++ 函数返回字符串数组

    我是 C 新手 对于一个学校项目 我需要创建一个能够返回字符串数组的函数 目前我的标题中有这个 Config h string getVehicles void 配置文件 string Config getVehicles string t
  • docker-compose:删除容器名称的默认后缀?

    my yml version 3 services myservice image myimage 当我跑步时docker compose p myprefix f my yml up 它创建名为myprefix myservice 1 是
  • 如何在没有数据库锁的情况下并行执行线程并在sqlite数据库中插入相应的数据?

    我需要调用多个 api 每个 api 在单独的线程中执行 并将响应中的相应数据插入到 sqlite 数据库中 而不会导致锁定 任何人都可以在这方面帮助我提供一个我可以参考的工作示例 我需要调用多个 api 每个 api 在单独的线程中执行
  • 我应该在哪里存储外键?

    如果我在两个表之间存在关系 两个表都有自己的主键 那么什么应该指导我决定哪个表应该存储外键 我知道关系的性质可能很重要 一对一 一对多 多对多 单向 双向 并且访问模式可能也很重要 那么做出这个决定的系统方法是什么 关系中的子表是哪个表 回
  • 微服务架构松散耦合的复杂性

    我对整个微服务潮流相当陌生 我一直在研究良好的微服务环境背后的架构和原理 定义微服务的主要内容之一应该是每个服务的松散耦合性质 微服务A永远不应该打电话微服务B直接 或者您正在有效地创建一个整体系统 该系统失去了架构模式提供的可扩展性 问题
  • 如何获取由 vector::reserve() 分配的缓冲区的地址?

    我有一个 std vector 值 我知道其最大大小 但实际大小在使用过程中会有所不同 void setupBuffer const size t maxSize myVector reserve maxSize void addToBuf
  • 通过 hibernate 或连接池保证请求

    使用连接池的休眠是否需要重试来处理间歇性故障 例如网络问题 我的同事认为这不是使用连接池的必然原因 如果连接出现任何问题 那么连接池管理器会处理它 我不相信 因为连接可能是开放且有效的 但是当发出请求时 它可能会屈服于网络问题 由于正在做的
  • 异步和等待 - 处理对同一方法的多次调用 - 相互锁定/等待?

    我有一个复杂的基于任务 锁的混乱来执行 长 数据操作 并且我正在尝试用异步 等待替换它 我是异步等待的新手 所以我担心我犯了一些大错误 为了简化事情 我的 UI 有几个页面依赖于相同的数据 现在 我只需要获取这些数据一次 所以我缓存它 进一
  • 对字典中成员“下标”的引用不明确

    我正在尝试为类创建一个可失败的初始化程序 我的类将使用网络请求的输入进行初始化 网络不可靠 我想创建一个初始化程序来检查所有属性是否存在 否则会失败 我试图在这里使用守卫 所以请随时指出该方法中任何明显的错误 public class Jo
  • 特殊字符问题:MQ 消息 PUT 错误:java.nio.charset.UnmappableCharacterException

    我有一个设置 其中有 JMS 生产者和 JMS 接收器 发送者应用程序发送如下消息 source text abcdefg JMS 接收器收到消息后 使用纯 IBM MQ API 类将其放入 IBM MQ 队列 将此消息发送到 MQ 时 我