存反序列化数据时发生ClassNotFoundException

存反序列化数据时发生ClassNotFoundException

本文介绍了从缓存反序列化数据时发生ClassNotFoundException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于Web服务的EJB EAR应用程序,部署在Glassfish 3.0.1服务器上.关于pom.xml,所有依赖项都由maven加载.我正在使用wsimport从WSDL文件生成类.一切正常.

I have an EAR application with EJB for web services, deployed at Glassfish 3.0.1 server. All dependencies are loaded by maven, regarding to pom.xml. I am using wsimport for generate classes from WSDL files. Everything worked perfectly.

然后由于某些性能问题,我不得不为mybatis查询实现缓存.打开缓存后,我意识到我的类需要可序列化.这不是问题.

Then I had to implement caching for mybatis queries because of some performance issues. After I turn caching on, I realize, that my classes need to be serializable. This wasn't a problem.

<xs:annotation>
    <xs:appinfo>
        <jaxb:globalBindings>
            <xjc:serializable uid="1" />
        </jaxb:globalBindings>
    </xs:appinfo>
</xs:annotation>

已编译并部署了应用程序,但是当我第二次从soapUI调用Web服务操作(第一次确定,缓存为空)时,出现以下错误.

Application is compiled and deployed, but when i call web service operation for the second time (first time ok, cache is empty) from soapUI, i get following error.

org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: org.apache.ibatis.cache.CacheException: Error     deserializing object. Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
### Cause: org.apache.ibatis.cache.CacheException: Error deserializing object. Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
... some code ommited ...
Caused by: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:79)
at org.apache.ibatis.cache.decorators.SerializedCache.getObject(SerializedCache.java:35)
at org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:35)
at org.apache.ibatis.cache.decorators.SynchronizedCache.getObject(SynchronizedCache.java:40)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:56)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:78)
... 83 more
Caused by: java.lang.ClassNotFoundException: cz.cpost.esb.cenik.schema.CountryType
at com.sun.enterprise.loader.ASURLClassLoader.findClassData(ASURLClassLoader.java:713)
at com.sun.enterprise.loader.ASURLClassLoader.findClass(ASURLClassLoader.java:626)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at java.util.ArrayList.readObject(ArrayList.java:593)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:76)
... 88 more

当应用试图从缓存中获取数据时,似乎找不到对象CountryType.我不知道这怎么可能,我在Maven和缓存领域还很陌生.

It seems like when app is trying to get data from cache, cannot find object CountryType.I don't know how this is possible, I am pretty new in maven and caching.

Maven构建元素:

<build>
    <resources>
        <resource>
            <targetPath>META-INF/wsdl</targetPath>
            <directory>src/wsdl</directory>
            <includes/>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes/>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <compilerArguments>
                    <endorseddirs>${endorsed.dir}</endorseddirs>
                </compilerArguments>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-ejb-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <ejbVersion>3.1</ejbVersion>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <version>1.12</version>
            <executions>
                <execution>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                    <configuration>
                        <keep>true</keep>
                        <wsdlFiles>
                            <wsdlFile>CenikServices-v2.0.wsdl</wsdlFile>
                        </wsdlFiles>
                        <packageName>cz.cpost.esb.cenik.schema</packageName>
                        <staleFile>${project.build.directory}/jaxws/stale/cenik.stale</staleFile>
                        <bindingFiles>
                            <bindingFile>${basedir}/src/main/resources/jaxb-bindings.xml</bindingFile>
                        </bindingFiles>
                    </configuration>
                    <id>wsimport-generate-cenik</id>
                    <phase>generate-sources</phase>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>javax.xml</groupId>
                    <artifactId>webservices-api</artifactId>
                    <version>1.4</version>
                </dependency>
            </dependencies>
            <configuration>
                <sourceDestDir>${project.build.directory}/generated-sources/jaxws-wsimport</sourceDestDir>
                <destDir>${project.build.directory}/classes</destDir>
                <xnocompile>true</xnocompile>
                <verbose>true</verbose>
                <extension>true</extension>
                <catalog>${basedir}/src/jax-ws-catalog.xml</catalog>
                <target>2.0</target>
            </configuration>
        </plugin>
    </plugins>
</build>

映射器配置中的缓存配置:

<cache type="org.mybatis.caches.ehcache.EhcacheCache">
    <property name="timeToIdleSeconds" value="7200"/>
    <property name="timeToLiveSeconds" value="28800"/>
    <property name="maxElementsInMemory" value="5000"/>
    <property name="maxElementsOnDisk" value="10000"/>
    <property name="memoryStoreEvictionPolicy" value="LRU"/>
 </cache>

尽管我的资源不在classpath中,但我将archive元素放到了pom.xml的耳朵中:

I though my sources is not in classpath and I put archive element to ear pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
    <groupId>cz.cpost.esb</groupId>
    <artifactId>cenikservices-ear</artifactId>
    <version>2.0</version>
    <relativePath>../pom.xml</relativePath>
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>ear</artifactId>
<packaging>ear</packaging>

<dependencies>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>cenikservices-ejb</artifactId>
        <version>${project.version}</version>
        <type>ejb</type>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-ear-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <defaultLibBundleDir>lib</defaultLibBundleDir>
                <modules>
                    <ejbModule>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>cenikservices-ejb</artifactId>
                    </ejbModule>
                </modules>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

EAR文件结构:

但是问题没有解决.为什么应用程序找不到打包在cenikservices-ejb-2.0.jar中的生成的源?

But problem is not solved. Why application could not find generated sources packaged in cenikservices-ejb-2.0.jar?

更新

我将EJB类的行添加到其构造函数中

I added lines to my EJB class into its constructor

import org.apache.ibatis.io.Resources;
...
public CenikEJB() {
    Resources.setDefaultClassLoader(this.getClass().getClassLoader());        // added
    this.sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();
}

但在ASURLClassLoader上仍然出现相同的错误:-(我测试了是否可以在EJB方法中使用CountryType类.我在日志中看到成功.

but still get the same error on ASURLClassLoader :-(I tested, if class CountryType is available in EJB method and it is. I see SUCCESS in log.

@Override
public List<CountryType> listCountry(Integer codeTask, String langAlfaCode) throws CenikFault {
    methodName = "Cenik.listCountry";

    SqlSession session = this.sqlSessionFactory.openSession();
    try {
        this.getClass().getClassLoader().loadClass("cz.cpost.esb.cenik.schema.CountryType");
        ccpLogger.info( "SUCCESS    - Pokus o nalezeni tridy CountryType vysel");
    } catch (ClassNotFoundException ex) {
        ccpLogger.info("FAIL        - Pokus o nalezeni tridy CountryType nevysel",ex);
    }

    try
    {
        ListCountryType param = this.of.createListCountryType();
        param.setCodeTask(codeTask);
        param.setLangAlfaCode(langAlfaCode);

        // ziskat seznam zemi pomoci SQL procedury
        List seznamZemi = session.selectList("Cenik.getListCountry", param);

        return seznamZemi;
    } catch (IllegalArgumentException ex) {
        ccpLogger.error(methodName,ex);
                    ...

    } catch (Exception ex) {
        ccpLogger.error(methodName,ex);
                    ...
    } finally {
        session.close();
    }
}

推荐答案

问题是服务器端无法加载类cz.cpost.esb.cenik.schema.CountryType.

The problem is that the server side can't load the class cz.cpost.esb.cenik.schema.CountryType.

最可能的原因是,定义该类的JAR文件未包含在您部署的EAR文件中.对此的最可能的解释是,EAR项目的POM文件不具有所需格式的必需依赖项.

The most likely cause is that the JAR file that defines that class can not been included in the EAR file that you deployed. And the most likely explanation for that is that the POM file for the EAR project doesn't have the required dependency in the required form.

请注意,相关性应在POM文件的顶级<dependencies>元素中列出;即作为<project>元素的子元素.

Note that the dependencies should be listed in a <dependencies> element at the top level on the POM file; i.e. as a child element of the <project> element.

第一步应该是检查包含该类的JAR文件是否确实在已部署的Webapp中. (是的,那么问题就出在别的东西上……)

The first step should be to check whether the JAR file that contains that class is actually in the deployed webapp. (It it is, then the problem is something else ...)

然后,您需要将必要的依赖项添加到EAR模块的POM文件中.

Then you need to add the requisite dependencies to the EAR module's POM file.

更新

根据您提供的其他信息,我认为这是Ibatis的类加载问题.看来,Ibatis尝试使用不包含您的类的类加载器来加载类. (我的猜测是,Ibatis使用的是公共类"类加载器……其中不包括您的应用程序JAR.)

Based on the additional information you provided, I think that it is a problem with Ibatis' class loading. It appears that Ibatis is attempting to load the class using a class loader that doesn't include your classes. (My guess is that Ibatis is using the "common classes" class loader ... which doesn't include your application JARs.)

显然,解决方法是在servlet类中完成此操作:

Apparently, the fix is to do this in your servlet class:

    import com.ibatis.common.resources.Resources;
    ...
    Resources.setDefaultClassLoader(this.getClass().getClassLoader());

参考文献:

  • http://sfranklyn.wordpress.com/2005/12/07/how_to_run_ibatis_in/
  • Glassfish Classloaders

更新#2

我正在猜测...但是这个错误报告( http://code.google.com/p/mybatis/issues/detail?id=622 )似乎正在描述MyBatis 3.x中的错误,其中setDefaultClassLoader无法正常工作.他们似乎在说已在3.2.2中修复".我注意到您正在使用3.0.5.看看将POM的依赖关系更新到更高版本是否有帮助.

I'm guessing at this point ... but this bug report (http://code.google.com/p/mybatis/issues/detail?id=622) seems to be describing a bug in MyBatis 3.x where setDefaultClassLoader is not working. They seem to be saying "fixed in 3.2.2". I notice that you are using 3.0.5. See if updating your POM's dependency to a later version helps.

如果没有,我建议的最好办法是将调试器附加到Glassfish实例,看看是否可以找出正在使用的类加载器...以及原因.显然,这是一个类加载器问题.

If not, the best I can suggest is to attach a debugger to your Glassfish instance and see if you can dig out what classloader it is using ... and why. It seems pretty clear that it is a classloader issue.

这篇关于从缓存反序列化数据时发生ClassNotFoundException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 09:26