У меня есть приложение EAR с EJB для веб-сервисов, развернутое на сервере Glassfish 3.0.1. Все зависимости загружаются maven, относящиеся к pom.xml. Я использую wsimport для генерации классов из файлов WSDL. Все отлично работало.ClassNotFoundException при десериализации данных из кеша
Затем мне пришлось реализовать кэширование запросов mybatis из-за некоторых проблем с производительностью. После того, как я включил кеширование, я понимаю, что мои классы должны быть сериализуемыми. Это не проблема.
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings>
<xjc:serializable uid="1" />
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
Применение компилируется и развертывается, но когда я называю работу веб-службы во второй раз (первый раз нормально, кэш пуст) из SoapUI, я получаю следующее сообщение об ошибке.
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 и кешировании.
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>
я, хотя мои источники не в пути к классам, и я поставил архивный элемент уха 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?
UPDATE
Я добавил строки в моем классе EJB в его конструктор
import org.apache.ibatis.io.Resources;
...
public CenikEJB() {
Resources.setDefaultClassLoader(this.getClass().getClassLoader()); // added
this.sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();
}
, но все еще получаю ту же ошибку на ASURLClassLoader :-( Я проверил, если класс CountryType является доступный в EJB-методе, и есть. Я вижу УСПЕХ в журнале.
@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();
}
}
У вас есть serialversionUID в рассматриваемом классе? – Thihara
Благодарим за комментарий. Да, у меня есть 'private final static long serialVersionUID = 1L;' во всех моих классах, сгенерированных wsimport. Но serialVersionUID устанавливается одинаково для каждого класса. Это может быть проблема? – Worsik
Нет, если это то же самое, это не должно быть проблемой ... Ну, если нет двух версий со структурными различиями. – Thihara