GlassFish中的一个Bug

最近在研究EJB3,经常使用GlassFish。按照JavaEE规范,如果在EJB3的远程接口中需要传递自定义的数据类型,只要让定义的类实现java.io.Serializable接口,然后保证类中每一个字段都是实现了java.io.Serializable接口即可进行远程数据传递。比如一个远程接口的定义如下:

@javax.ejb.Remote
public interface ProductManager {

   java.util.List<po.Product> findAll();
   //.....
}

则po.Product类的定义则应该如下:
public class Product implements java.io.Serializable{
  private int no;
  private String name;
  private String from;
  //...
}

原来经常写这样的代码,也没有出过什么问题。但这次偏偏问题就来了。在创建一个EJB项目,完成代码后,部署到GlassFish之后(项目采用的是GlassFish中的目录部署模式),利用远程的Java客户端调用findAll方法时,却总是出现这样的错误:
"IOP02400001: (DATA_CONVERSION) 字符未映射至协商的传输代码集"
org.omg.CORBA.DATA_CONVERSION:   vmcid: OMG  minor code: 1  completed: No
        at com.sun.corba.ee.impl.logging.OMGSystemException.charNotInCodeset(OMGSystemException.java:2093)
        at com.sun.corba.ee.impl.logging.OMGSystemException.charNotInCodeset(OMGSystemException.java:2111)
        at com.sun.corba.ee.impl.encoding.CodeSetConversion$JavaCTBConverter.convertCharArray(CodeSetConversion.java:336)
        at com.sun.corba.ee.impl.encoding.CodeSetConversion$JavaCTBConverter.convert(CodeSetConversion.java:249)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.writeString(CDROutputStream_1_0.java:504)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.write_string(CDROutputStream_1_0.java:493)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.write_codebase(CDROutputStream_1_0.java:1379)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.writeValueTag(CDROutputStream_1_0.java:1423)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.writeRMIIIOPValueType(CDROutputStream_1_0.java:815)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.write_value(CDROutputStream_1_0.java:935)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.write_value(CDROutputStream_1_0.java:949)
        at com.sun.corba.ee.impl.encoding.CDROutputStream_1_0.write_value(CDROutputStream_1_0.java:690)
        at com.sun.corba.ee.impl.encoding.CDROutputStream.write_value(CDROutputStream.java:451)
        at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl$14.write(DynamicMethodMarshallerImpl.java:376)
        at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl.writeResult(DynamicMethodMarshallerImpl.java:472)
        at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:158)
        at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
        at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
        at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
        at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Caused by: java.nio.charset.UnmappableCharacterException: Input length = 1
        at java.nio.charset.CoderResult.throwException(CoderResult.java:261)
        at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:771)
        at com.sun.corba.ee.impl.encoding.CodeSetConversion$JavaCTBConverter.convertCharArray(CodeSetConversion.java:321)
        ... 23 more


利用调试和跟踪工具,发现就是在findAll方法在回传结果时抛出的异常。开始觉得这个错误有些莫名奇妙,后来发现,我的项目的所在的目录位于Windows的“我的文档”目录中,而我的文档对应的用户名是中文。于是我换了一个纯英文目录存储项目,然后再在GlassFish中部署,就一切OK了!

看来,这是GlassFish的一个Bug:

如果你在远程商业方法中传递的自己定义的类的实例,那么请确保项目部署的目录所在的路径中没有中文的文件夹,否则会产生上述错误。

如果回传的数据是Java中的基础类库中的类型,比如String、int这样的简单数据类型,则不会产生这个错误。

这里也希望各位朋友注意这个问题,其实,这个中文路径的问题不只限于GlassFish,如果你在JavaSE项目中使用基于TopLink的JPA,假如你的程序运行所在的目录是中文,或该目录位于一个包含中文的路径中,也会遇到TopLink报告的不能正常初始化持久单元的错误。所以,在Java开发时,应避免使用包含有中文目录的路径。

你可能感兴趣的:(java,jpa,ejb,sun,Glassfish)