2011-12-19 59 views
2

我使用的MyBatis與playframework和一切工作很好,除了:CacheException - 錯誤反序列化對象 - 的MyBatis和播放

當我試圖使用內置MyBatis中默認的緩存(在XML映射文件<cache/>標籤) ,在檢索一個緩存的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實現Serializable!

這裏是堆棧跟蹤:

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

對不起,我想我是錯的 - 這是不是一個名字碰撞,而是一個類加載器的問題。

Play使用動態類加載機制來檢測對源代碼的更改並通過字節碼注入增強方法。 http://groups.google.com/group/play-framework/browse_frm/thread/359736394ae27902/98445c557833036c

我認爲問題可能是MyBatis使用常規類加載器 - 所以無法找到通過Play機制加載的類。將源文件放入Play目錄後,MyBatis將使用Play類加載器。

這裏有一些選擇:

1)編譯你的域對象到一個JAR文件。包括在您的項目中的jar:http://groups.google.com/group/play-framework/browse_thread/thread/b54e4e25ae49161b

2)強制的MyBatis使用播放類加載器 - 任何MyBatis的要求在什麼地方

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

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

似乎仍像一個黑客,但也許它讓你應用程序源大小下降。

3)確保您的類在調用MyBatis之前被加載。所以,在這種情況下。

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

這似乎更糟糕的黑客。

我希望其中的一個選項適合您。

+0

我添加你需要的額外的信息。 – Bogdan 2011-12-19 15:20:21

+0

基於你的修復,它聽起來像它可能是一個類名衝突。通過在項目中編譯它們,您可以更改訂單。 – 2011-12-19 19:39:36

+0

如果使用「Open Type」(eclipse中的ctrl + shift + T),您會看到多少個Serializable類(假定您使用的是eclipse)。 – 2011-12-19 19:40:41

0

更新:隨着當前版本中包含的修補程序#530一切都按預期工作。

Play 1.x用戶可能對MyBatisPlay模塊感興趣,我正在維護它。這在開發中非常有用,因爲它會在java源文件或xml映射器配置發生更改時重置會話工廠,從而避免重新啓動Web應用程序。

原帖: 我發現了一個解決辦法:

  • 如果我對MyBatis的源文件複製應用程序目錄下(我讓遊戲框架編譯成通常情況下),並刪除iBatis的預編譯的jar從lib目錄中,它按預期工作。

不過,我正在尋找一個更好的解決辦法,不聽起來像一個黑客:)

謝謝!

+0

你用3.1.1試過了嗎? – 2012-06-23 07:27:47

+0

@DiegoLopez對不起,我應該在這裏更新了這個信息。我實際上是提交問題#530補丁的人。所以,是的,它現在正常工作:)。謝謝! – Bogdan 2012-06-23 08:04:19