`
RednaxelaFX
  • 浏览: 3053509 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

碰到jBPM的编码问题了 T T

    博客分类:
  • Java
阅读更多
上周在写某东西的时候,要用jBPM来部署流程,数据来源是Saito同学传来的XML字符串。但是只要XML里一有中文,部署就会失败。而且在写的那东西极其不好调试——程序里很多地方都被proxy包装过的话,调试起来会很痛苦。
大概的状况是:Saito同学传来的XML字符串不包含XML声明,我这边调用jBPM新建NewDeployment,把字符串放进去,然后deploy,然后就抛出个被包装了很多层的异常,其中最内层的是MalformedByteSequenceException。
之前还有别的更头疼的问题要解决,这个问题就放在了一边。周五的时候终于有时间去修一修。

抓来jBPM 4.1的源码一看,囧了。在我调用jBPM的地方,传入的XML字符串大概经过了下面一些方法才被解析为DOM:

org.jbpm.pvm.internal.repository.DeploymentImpl:
public NewDeployment addResourceFromString(String resourceName, String text) {
  addResourceFromStreamInput(resourceName, new StringStreamInput(text));
  return this;
}


org.jbpm.pvm.internal.stream.StringStreamInput:
public class StringStreamInput extends StreamInput {
  
  String string;
  
  public StringStreamInput(String string) {
    this.name = "string";
    this.string = string;
  }

  public InputStream openStream() {
    byte[] bytes = string.getBytes();
    return new ByteArrayInputStream(bytes);
  }
}


org.jbpm.pvm.internal.xml.Parse:
protected InputSource getInputSource() {
  if (inputSource!=null) {
    return inputSource;
  }

  if (streamInput!=null) {
    inputStream = streamInput.openStream();
    return new InputSource(inputStream);
  }
  
  addProblem("no source specified to parse");
  return null;
}


org.jbpm.pvm.internal.xml.Parser:
protected Document buildDom(Parse parse) {
  Document document = null;

  try {
    SAXParser saxParser = saxParserFactory.newSAXParser();
    XMLReader xmlReader = saxParser.getXMLReader();
    
    // ...
    
    InputSource inputSource = parse.getInputSource(); 
    xmlReader.parse(inputSource);

  } catch (Exception e) {
    parse.addProblem("couldn't parse xml document", e);
  }

  return document;
}


总之绕了各种接口,经过层层包装、拆包、再包装再拆包,可怜的字符串终于来到SAX解析器的手上。问题是jBPM在中间调用了String.getBytes():这个方法会把Java字符串(Unicode)转换为系统默认编码并返回对应的byte[],但当InputSource中没有设置编码信息时,SAXParser默认是以UTF-8编码来读取输入流的。我的开发机的系统默认编码是GBK,于是就出问题了。jBPM用String.getBytes()让我无语了……就不能用带编码参数的版本么 T T

简单再现这个问题可以用下面这个程序:
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;

public class TestSAX {
  private static InputSource getInputSource(String src) {
    return new InputSource(new ByteArrayInputStream(src.getBytes()));
  }
  
  public static void main(String[] args) throws Exception {
    String xmlStr = "<test name=\"名称\"></test>";
    System.out.println(xmlStr);
    
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    SAXParser saxParser = saxParserFactory.newSAXParser();
    XMLReader xmlReader = saxParser.getXMLReader();
    
    InputSource input = getInputSource(xmlStr);
    xmlReader.parse(input);
  }
}

运行它会看到:
D:\temp>java TestSAX
<test name="名称"></test>
Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte UTF-8 sequence.
        at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.scanLiteral(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLScanner.scanAttributeValue(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanAttribute(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$ContentDriver.scanRootElementHook(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
        at TestSAX.main(TestSAX.java:19)


稍微修改,加上对应本机器的系统默认编码的XML声明后,问题就解决了:
import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;

public class TestSAX {
  private static InputSource getInputSource(String src) {
    return new InputSource(new ByteArrayInputStream(src.getBytes()));
  }
  
  public static void main(String[] args) throws Exception {
    String xmlStr = "<?xml version=\"1.0\" encoding=\"" + System.getProperty("file.encoding") + "\"?><test name=\"名称\"></test>";
    System.out.println(xmlStr);
    
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    SAXParser saxParser = saxParserFactory.newSAXParser();
    XMLReader xmlReader = saxParser.getXMLReader();
    
    InputSource input = getInputSource(xmlStr);
    xmlReader.parse(input);
  }
}


这让我想起以前在developerWorks读过的一篇文章,Tip: Always use an XML declaration。确实是应该写上XML声明的。

不过随便乱写一个XML声明却不管用。如果把上例的XML声明中的编码改为"UTF-8",在我这默认GBK的系统上跑照样是碰到MalformedByteSequenceException错误。考虑到我不应该依赖于定测试环境和线上环境的编码到底是什么,这里就用System.getProperty("file.encoding")去获取系统默认编码,以便于String.getBytes()匹配。
分享到:
评论
4 楼 RednaxelaFX 2010-03-16  
DT1 写道
只是还是觉得有点恶心,这个编码其实应该从xml文件中读取,而不是写死,要不然人家上传的是GBK不是郁闷.

其实有从XML文件里读的咯,当XML文件开头的编码声明是正确的时候SAXParser就能正确解析出来。当没有开头的编码声明时,受到String.getBytes()的影响而变得是使用了系统默认编码来读。上面文中也提到了。
3 楼 DT1 2010-03-15  
可使用以下方法解决,在你这边留个影,让其他找到的朋友可以有个解决方案:
processEngine.getRepositoryService().createDeployment() .addResourceFromInputStream("xxxx.jpdl.xml", IOUtils.toInputStream(xml, "utf-8")).deploy();

显式指定传入InputStream以及编码,将xml转成InputStream,就可以解决这个问题.
只是还是觉得有点恶心,这个编码其实应该从xml文件中读取,而不是写死,要不然人家上传的是GBK不是郁闷.
2 楼 DT1 2010-03-15  
看了代码了,这个问题还是在那里,使用.getBytes时,看起来是默认使用当前系统的编码集.
1 楼 DT1 2010-03-14  
半夜遇到同样问题,我是4.3,我认为是它的getBytes有问题,它不应该getBytes,而应该直接将到后台去处理,因为前台已经传入是string了,而不是什么inputstream之类的.

相关推荐

    jbpm4.3问题解决

    本篇主要针对jbpm4.3使用过程中遇到的问题及其解决方法进行详细阐述。 首先,我们来看"jbpm4_3表结构和表字段说明 - gamestart104的专栏 - 博客频道 - CSDN_NET.htm"这个文件,这通常包含了jbpm4.3在数据库中使用的...

    jbpm4jbpm5

    jbpm4jbpm5是关于jbpm流程管理框架的专题,涵盖了jbpm4和jbpm5两个主要版本。jbpm是一个开源的工作流管理系统,用于帮助开发者实现业务流程自动化。以下是基于给定文件的信息,深入解析jbpm4和jbpm5的知识点: 1. *...

    jbpm简介\jbpm简介

    ### jBPM简介与关键技术知识点 #### 一、jBPM概述 jBPM是一个开源的、纯Java的、轻量级的商业流程管理(Business Process Management, BPM)工作流引擎。它支持多种可执行流程语言,并且可以在任何JavaEE应用...

    jbpm jbpm4.3.jar

    jbpm jbpm4.3.jar DDDDDDDD

    jbpm 案例 jbpm jbpm

    jbpm使用案例,非常不错,大家都来看看吧。

    jbpm开发指南--jbpm全面介绍

    通过查看JBPM的API我们发现API里并没有提供实现该功能现成的接口,不过我们可以通过自己手工编码的方式来拿到我们需要的监控信息。 通过查看JBPM的表,我们知道要实现流程监控功能就是把JBPM当中的JBPM_PROCESS...

    jbpm的eclipse的流程设计器插件designer中的gpd.xml文件乱码问题

    总之,解决jbpm的Eclipse Designer插件中gpd.xml文件乱码问题的关键在于确认并保持文件和编辑器之间的一致性,确保使用的都是正确的字符编码。同时,了解Eclipse和相关插件的配置设置,以及如何正确处理XML文件,将...

    配置Jbpm注意问题

    在配置Jbpm的过程中,可能会遇到一系列的问题,尤其是在与数据库集成和服务器环境设置时。本文将详细探讨在配置Jbpm时需要注意的关键点,包括MySQL字符集问题、Jboss服务器的配置以及JBossJbpm的整合。 首先,MySQL...

    jbpm4.3 中文乱码解决

    jbpm4.3插件,解决中文乱码,主要修改org.jboss.tools.flow.jpdl4_4.3.0.v201007071649.jar中的JbpmLocationsPage 和 org.jboss.tools.jbpm.common_4.3.0.v201007071649.jar 中的JpdlSerializer和ProcessSerializer

    jbpm白皮书 介绍jbpm 入门

    ### jBPM 白皮书:介绍 jBPM 入门 #### 一、引言与背景 在当今数字化转型的时代背景下,业务流程管理(Business Process Management,简称 BPM)成为了企业提升效率、优化流程的关键技术之一。BPM 提供了一种程序...

    jbpm

    【jbpm】是一种开源的工作流管理系统,全称为Java Business Process Management。它主要用于处理业务流程的自动化,通过定义和执行工作流程来协调应用系统中的不同组件。jbpm不仅提供了流程建模、部署、执行的能力,...

    jbpm4.3常见问题解决

    首先,我们来看"jBPM-4.x常见问题解决方案FAQ.docx",这个文档很可能包含了用户在使用jBPM 4.3时遇到的各种问题和相应的解决办法。常见问题可能包括流程部署失败、任务无法执行、数据持久化问题、工作流引擎性能优化...

    jBPM3.2.rar_JBPM3.2_jbpm_jbpm 3.2_jbpm3_jbpm3.2教程

    你可以通过阅读这个文档,深入了解jbPM 3.2的使用方法,解决在实际项目中遇到的问题。 总的来说,jbPM 3.2是一个强大的工作流管理系统,通过深入理解和实践,开发者可以构建出高效、灵活的业务流程,提高企业的业务...

    jbpm-3.1.2.zip_jbpm_jbpm 3.1.2_jbpm-3.1.2.rar_jbpm3.1.2_工作流

    jbpm-3.1.2.zip 文件包含了 jBpm 的一个重要版本——jBpm 3.1.2,这是一个开源的工作流管理系统,专为构建灵活且可扩展的业务流程解决方案而设计。jBpm 提供了一种方式,使得开发者能够用简单而强大的语言来表达业务...

    JBPM4 SSH EXTJS JBPM SSH EXTJS

    JBPM4 SSH EXTJS JBPM SSH EXTJS JBPM4 SSH EXTJS JBPM SSH EXTJS JBPM4 SSH EXTJS JBPM SSH EXTJS JBPM4 SSH EXTJS JBPM SSH EXTJS 希望对大家有帮助。

    jBPM4.4.rar_jbpm4.4_jbpm4.4 PDF

    在《jBPM4.4中文用户手册》中,用户可以找到更详细的使用指南,包括安装配置、基本操作、示例教程以及常见问题解答等内容。手册将帮助用户快速上手,实现jBPM在实际项目中的应用。 总的来说,jBPM4.4是企业级业务...

    jbpm数据库表介绍

    jbpm 数据库表介绍 jbpm 是一个基于 Java 的 workflow 引擎,用于管理和执行业务流程。jbpm 需要持久化流程部署、流程实例、任务、用户认证等信息,于是 jbpm 设计了一系列的数据库表来存储这些信息。在 jbpm 4.4 ...

    jbpm学习资料,jbpm教程

    jbpm(Java Business Process Management)是一款开源的工作流管理系统,它为业务流程自动化提供了一套全面的解决方案。jbpm不仅支持工作流的建模、执行,还提供了监控和管理功能,使得开发者可以方便地构建和部署...

    jbpm+ssh整合

    在实际开发中,关键点在于解决jbpm和Hibernate的session冲突问题。jbpm需要自己的session来执行工作流操作,而SSH框架通常有自己的持久化机制。这里可以利用Spring的Transaction Management,统一管理事务和session...

Global site tag (gtag.js) - Google Analytics