关于castor.jar中java.lang.ClassCastException是问题

全段时间在使用castor包来实现对象属性值的设置,使用过的人应该都清楚。

1.需要加载对象的配置文件,代码如下:

InputSource is = new InputSource(getMappingFileStream(objName + "-mapping.xml"));
Mapping mapping = new Mapping();
mapping.loadMapping(is);

2.创建Unmarshaller对象并且设置mapping对象

Unmarshaller un = new Unmarshaller(mapping);

3.加载加载数据文件,并且返回创建的对象

InputSource dataIs = new InputSource(getConfigureFileStream(objName + ".xml"));
obj = (T) un.unmarshal(dataIs);

这样就完成了所有操作。但是你们是否遇到过在某些情况下会抛出java.lang.ClassCastException而且为这个异常感到莫名其妙呢?其实原因就在于classloader的问题了。

之前遇到这个问题的时候我也是一筹莫展,话了好多时间来跟代码,但是第三方包的代码确实不好跟,所以我反编译了一些。当然其实这个问题还是在我在ibm网站上看到一篇文章才有所进展,文章是这样说的,

WebSphere Application Server V5 classloaders
There is, by design, a hierarchy of classloaders in WebSphere Application Server V5. The main ones we are interested in are:
WebSphere Extension Classloader 
^ 
^ 
EAR Classloader 
^ 
^ 
WAR Classloader 

There are two related concepts associated with classloaders:
Visibility
defines which classes are "reachable" -- that is, which classes can be loaded. Normally, visibility extends "up" but not "down". Therefore, any class loaded by a WAR classloader can also load classes using the EAR or WASext classloader, but any class loaded by the EAR (or WASext) classloader cannot subsequently load classes using the WAR classloader.
Delegation
defines the "preference" order of classloaders. In other words, it defines where to look first (and subsequently if necessary) to try to load classes. Within WebSphere Application Server V5, each J2EE module classloader has a setting (PARENT_FIRST or PARENT_LAST) that you can use to set the delegation mode for the EAR and WAR (but not for anything higher).

这里也提一下,原本测试环境就是eclipse 1.6/1.5环境测试是没有问题,但是我们项目是在jboss下运行的。所以我就想是不是jboss也可能存在这样的问题呢。于是我就按照上面说的方法试试,

The solution
To work around this, your utility class code must:
Get the currently executing thread contextclassloader and save it, as shown below: 
ClassLoader savedClassloader = Thread.currentThread().getContextClassloader();
Set the contextclassloader to its own classloader, as shown below:
Thread.currentThread().setContextClassloader( this.getClass().getClassLoader() );
Invoke the Xerces parsing operations it needs to use
Restore the contextclassloader, as shown below:
Thread.currentThread().setContextClassloader( savedClassLoader );
By performing the above steps, your utility class can safely be in the classloader hierarchy above PARENT_LAST J2EE modules that include their own version of Xerces.
Whenever a WebSphere run-time class uses Xerces, WebSphere has to similarly modify all such classes to save the contextclassloader, explicitly use the WASext classloader to load Xerces and perform the parsing operations, and then restore the contextclassloader.
但是问题还是没有解决,在创建Unmarshaller的时候又抛出了别的异常,不过证明改变classloader起到了一定的作用,于是我觉得沿着这条路应该能解决这个问题,最后由于一个意外的发现让我看到了希望,我发现Unmarshaller在创建的时候代码里面好像有设置classloader的代码,而且Unmarshaller和Mapping也有带ClassLoader的构造函数,所以我试着将构造函数传入到这两个对象当中。

ClassLoader savedClassloader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());

Mapping mapping = new Mapping(this.getClass().getClassLoader());
mapping.loadMapping(is);

Unmarshaller un = new Unmarshaller(null, this.getClass().getClassLoader());
un.setMapping(mapping);

InputSource dataIs = new InputSource(fisConfigure);
obj = (T) un.unmarshal(dataIs);
Thread.currentThread().setContextClassLoader(savedClassloader);

OH......到此为止问题终于得到了解决。今天把这个问题记录下来也就是希望当有人遇到这样问题的时候不用像我一样再花好几天也解决不了问题了。 微笑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值