【问题标题】:Re-serializing JBPM process variables directly via MySQL直接通过 MySQL 重新序列化 JBPM 流程变量
【发布时间】:2011-08-30 17:42:52
【问题描述】:

我正在使用一个使用 JBPM 3.1 和 MySQL 的应用程序。核心问题是,有些流程实例的变量包含旧版本的外部非 JBPM Serializable 类。当主应用程序升级时,这些流程实例会导致 JBPM 抛出异常,因为主应用程序中特定类实例的 SUID 已更改。

我相信我有一种方法可以使用以下描述的技术来修复反序列化过程:

How to deserialize an object persisted in a db now when the object has different serialVersionUID

但是,我的问题是找出 MySQL JBPM 中存储流程实例变量的位置,因此我可以编写一个程序,该程序可以对所有实例的所有变量进行交互,重新序列化变量,以便有问题的类将具有新的 SUID,因此 JBPM 可以针对流程进行操作。

我最初查看 JBPM 表时,似乎 JBPM_BYTEARRAY 和/或 JBPM_BYTEBLOCK 可能是要操作的表。但是,我不确定如何进行。我猜每个流程变量都存储在一个包装容器类中。那堂课是org.jbpm.context.exe.VariableInstance吗?还是别的什么?

我想如果我在类路径中有正确的 jar 文件,并且我知道 JBPM 用于在 MySQL 中存储流程变量的主类实例是什么,我可以反序列化该类(这将解决 SUID 问题嵌入式问题类实例),并重新序列化该类。由于 JBPM 文档确实提到了有关转换器的内容,因此我不确定是否必须复制 JPBM 在反序列化时执行的转换过程,或者标准 java 反序列化是否足够。

【问题讨论】:

    标签: java mysql jbpm


    【解决方案1】:

    您知道您所做的更改是否违反了合同,还是只是简单地添加了新字段?如果它只是简单地添加新字段,那么只需定义先前的 serialversionuid.. 否则.. 您将必须读取所有具有不同 serialversionids 的变量并将它们保存在新类下,因为您是唯一知道如何转换它们的人。

    【讨论】:

    • 这应该是一个评论,但我不能只设置 SUID,因为他们是序列化类的新版本的客户,所以如果 SUID 设置为旧值,那么这些客户会有反序列化问题。
    • 我没有看到您的答案中如何处理旧的序列化对象。
    • 当 JRE 库调用 readLong() 时,我返回的是当前类的 SUID long 值,而不是序列化数据中的 SUID 值。这样 SUID 检查就会通过。当然,正如我所指出的,我的 readLong() 实现应该只在我的 ObjectInputStream 实现(它只是对基本实现的监视包装器)发生给定调用模式时才执行此操作。
    【解决方案2】:

    对 JBPM 的一些分析表明,二进制数据可能会被拆分到多个记录中。 mysql本身可能不是这样,但是JPBM代码是为了支持多个RDBM而编写的,并且有些对二进制记录的大小有限制。

    由于这个问题为我赢得了风滚草奖励,我不会在我必须满足的最后期限内得到一个可用的基于 mysql 的答案,所以我重新考虑了核心问题和问题发生的操作环境,并且想出了一个避免直接执行 mysql 操作的解决方案。

    有问题的主应用程序已经对 JBPM 进行了一些自定义修改,因此我实施的解决方案更改了 JBPM 源代码,它执行流程实例变量的反序列化。这避免了处理从 RDBM 中提取反序列化二进制数据的 JBPM 逻辑的需要。

    org.jbpm.context.exe.converter.SerializableToByteArrayConverter 类中,我修改了代码以使用自定义ObjectInputStream 类,该类返回一个类的最新SUID。如果新类包含新字段,则仅使用问题中引用的帖子中描述的最新版本的类替换描述符的技术不起作用。这样做会导致数据结束异常,因为基本反序列化代码会尝试访问该类的旧反序列化版本中的“新”字段。

    因此,我只需要替换 SUID,但保持描述符的所有其他部分相同。由于 JDK 没有使 ObjectStreamClass 可扩展,我创建了一个 ObjectInputStream 的子类,它基于 java 库在反序列化数据时针对 ObjectInputStream 执行的给定调用模式返回新的 SUID。

    模式:读取反序列化对象的标头时,调用readUTF() 函数(以获取类名),然后调用readLong()。因此,如果发生这种调用顺序,并且如果 readUTF() 返回了我要更改其 SUID 的类名,我将在 readLong() 调用中返回较新的 SUID。

    自定义代码读取一个配置文件,该文件指定类名和关联的 SUID,这些 SUID 应映射到列出的类的最新 SUID。这允许将来在不修改自定义代码的情况下映射备用类。

    注意,这种方法适用于一般的反序列化操作,其中需要将旧的 SUID 映射到指定类的最新 SUID,并保留序列化类描述符的其他部分以避免数据结束问题,如果较新的类定义包括旧类定义中不存在的附加字段声明。

    【讨论】:

    • 我感觉到你的痛苦:风滚草徽章..嘿
    猜你喜欢
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 2018-02-13
    相关资源
    最近更新 更多