CacheException - Ошибка десериализации объекта - MyBatis and Play - PullRequest
2 голосов
/ 19 декабря 2011

Я использую MyBatis с playframework, и все работает хорошо, кроме:

Когда я пытался использовать кэш по умолчанию, встроенный в MyBatis (тег <cache/> в файлах xml mapper), при получении кэшированного оператора select я получаю эту трассировку стека.

Если я выполняю одни и те же операторы в модульном тесте (или другом приложении без использования playframework), все работает нормально.

Итак, я полагаю, это как-то связано с тем, что playframework загружает / компилирует классы, что-то вроде проблемы загрузчика классов.

Макет каталога моего проекта выглядит примерно так (соответствующие биты):

app
  controllers
  data // xml mapping files and java interfaces for ibatis
       // & a class that returns a SqlSessionFactory
    domain // Pojos for SQL results (e.g. User.java)
  models
  views
lib // here is myibatis jar file
(...) // the rest of the standard play framework project

Метод модели, который вызывает исключение, таков:

  public static UserAuthentication findAuthenticatonIdentity(UserId userId){
    SqlSessionFactory sessionFactory = IbatisSessionFactory.getSqlMapper();
    SqlSession session = sessionFactory.openSession();
    AuthMapper authMapper = session.getMapper(AuthMapper.class);

    UserAuthentication ua = authMapper.selectByUserId(userId); // line 162
    session.close();
    return ua;
  }

А UserAuthentication реализует Сериализуемый!

А вот и трассировка стека:

Execution exception (In /app/models/UserModel.java around line 162)
PersistenceException occured : 
 ### Error querying database.  Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
 ### Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication

play.exceptions.JavaExecutionException: 
### Error querying database.  Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
### Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:231)
    at Invocation.HTTP Request(Play!)
Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
### Cause: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:94)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:58)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:90)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:40)
    at $Proxy8.selectByUserId(Unknown Source)
    at models.UserModel.findAuthenticatonIdentity(UserModel.java:162)
    at controllers.securesocial.MySecureSocial.checkAccess(MySecureSocial.java:97)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:504)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:478)
    at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:473)
    at play.mvc.ActionInvoker.handleBefores(ActionInvoker.java:322)
    at play.mvc.ActionInvoker.invoke(ActionInvoker.java:142)
    ... 1 more
Caused by: org.apache.ibatis.cache.CacheException: Error deserializing object.  Cause: java.lang.ClassNotFoundException: data.domain.UserAuthentication
    at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:94)
    at org.apache.ibatis.cache.decorators.SerializedCache.getObject(SerializedCache.java:50)
    at org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:50)
    at org.apache.ibatis.cache.decorators.SynchronizedCache.getObject(SynchronizedCache.java:55)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:72)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:100)
    ... 13 more
Caused by: java.lang.ClassNotFoundException: data.domain.UserAuthentication
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:603)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at java.util.ArrayList.readObject(ArrayList.java:593)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at org.apache.ibatis.cache.decorators.SerializedCache.deserialize(SerializedCache.java:91)
    ... 18 more

UserAuthentication.java

public class UserAuthentication implements Serializable {

  private int id;
  private String authId;
  private String secret;
  private String token; // Oauth1 token
  private String accessToken; // Oauth2 request token
  private String displayName;
  private String authMethod;
  private String provider;
  private String email;
  private String avatarUrl;
  private Date lastAccess;
  private String password;
  private boolean emailVerified;
  private int userId;
  private String activationUuid;
  private Date activationExpiry;

  // + getters & setters
}

UserId.java

public class UserId implements java.io.Serializable {
    /**
     * The id the user has in a external service.
     */
    public String id;

    /**
     * The provider this user belongs to.
     */
    public ProviderType provider; // simple enum
}

Ответы [ 3 ]

3 голосов
/ 19 декабря 2011

Извините, я думаю, что я ошибался - это не конфликт имен, а проблема загрузчика классов.

Play использует механизм динамической загрузки классов для обнаружения изменений в исходном коде и улучшения методов путем внедрения байт-кода.http://groups.google.com/group/play-framework/browse_frm/thread/359736394ae27902/98445c557833036c

Я думаю, что проблема может заключаться в том, что MyBatis использует обычный загрузчик классов - поэтому не может найти классы, которые загружаются через механизм Play.Когда вы помещаете источник в каталог Play, MyBatis затем использует загрузчик классов Play.

Вот несколько вариантов:

1) Скомпилируйте ваши доменные объекты в файл JAR.Включите эту флягу в ваш проект: http://groups.google.com/group/play-framework/browse_thread/thread/b54e4e25ae49161b

2) Заставьте MyBatis использовать загрузчик классов Play - где-нибудь до того, как mybatis вызовет

Thread.currentThread().setContextClassLoader(Play.classloader); 

http://groups.google.com/group/play-framework/browse_thread/thread/f4789ee5c20609af/d1412a914dc06851?#d1412a914dc06851

Stillкажется хаком, но, возможно, он уменьшает размер исходного кода вашего приложения.

3) Убедитесь, что ваши классы загружены перед вызовами MyBatis.Итак, в этом случае.

Class.forName("data.domain.UserAuthentication");
Class.forName("data.domain.UserId");

Что выглядит намного хуже хака.

Надеюсь, один из этих вариантов вам подойдет.

1 голос
/ 26 мая 2012

Только для записи, эта проблема была исправлена ​​в MyBatis 3.1.1

http://code.google.com/p/mybatis/issues/detail?id=530

0 голосов
/ 19 декабря 2011

ОБНОВЛЕНИЕ: С патчем # 530, включенным в текущую версию, все работает как положено.

Пользователи Play 1.x могут быть заинтересованы в модуле MyBatisPlay , которыйЯ поддерживаю.Это очень полезно в разработке, потому что оно сбрасывает фабрику сеанса, когда происходит изменение в исходных файлах java или конфигурации картографических данных xml, что исключает необходимость перезапуска веб-приложения.

Исходное сообщение: Я нашел обходной путь:

  • , если я скопирую исходные файлы для MyBatis в каталог приложения (я позволяю игровой платформе скомпилировать их как обычно) и удаляю предварительно скомпилированный jar ibatis из каталога lib, это работаеткак и ожидалось.

Однако я ищу лучшее решение, которое не похоже на взлом:)

Спасибо!

...