天天看點

又被古董級的庫坑了—— ibatis typehandler

為了将一個不知道什麼類型的java對象存到資料庫裡面,用了個很惡心的方法:将對象序列化之後,儲存到資料庫的blob對象。這樣整個序列化和反序列化過程,都期望在ibatis中完成,上層就能直接擷取到需要的對象了。

第一次安裝網上的方式,想直接參考spring的blobbytearraytypehandler,将blob對象儲存到資料庫。因為這個類是需要的是byte數組,還不滿足我的需求,就參照這個類,繼承了abstractlobtypehandler,重寫getresultinternal和setparameterinternal。然後将這個type handler配置到ibatis的sqlmap檔案中。一切看上去很順利,結果啟動的時候ibatis報classcastexception,說這個handler無法強制轉換成typehandlercallback。

這個異常看上去很奇怪,去網上搜尋了inlineparametermapparser類,裡面的邏輯大緻是:

[cce lang=”java”]

} else if (“handler”.equals(field)) {

try {

value = typehandlerfactory.resolvealias(value);

object impl = resources.instantiate(value);

if (impl instanceof typehandlercallback) {

mapping.settypehandler(new customtypehandler((typehandlercallback) impl));

} else if (impl instanceof typehandler) {

mapping.settypehandler((typehandler) impl);

} else {

throw new sqlmapexception (“the class ” + value + ” is not a valid implementation of typehandler or typehandlercallback”);

}

} catch (exception e) {

throw new sqlmapexception(“error loading class specified by handler field in ” + token + “. cause: ” + e, e);

[/cce]

也就是說,如果在sql中配置的handler是同時相容typehandlercallback和typehandler接口的,spring的abstractlobtypehandler類,實作的是basetypehandler,應該沒有問題的啊。

反編譯了應用中試用的ibatis(版本是2.1.6),發現裡面的邏輯完全不一樣:

mapping.settypehandler(new customtypehandler((typehandlercallback)resources.classforname(value).newinstance()));

throw new sqlmapexception(“unrecognized parameter mapping field: ‘” + field + “‘ in ” + token);

這個古董是直接初始化之後強轉為typehandlercallback的。沒辦法,隻能自己實作這個接口。

public class javaserializeblobhandler implements typehandlercallback {

/*

* (non-javadoc)

* @see com.ibatis.sqlmap.engine.type.typehandler#valueof(java.lang.string)

*/

public object valueof(string s) {

return s;

* @see

* com.ibatis.sqlmap.client.extensions.typehandlercallback#getresult(com.ibatis.sqlmap.client.extensions.resultgetter

* )

public object getresult(resultgetter paramresultgetter) throws sqlexception {

byte[] buf = paramresultgetter.getbytes();

if(buf == null) {

return null;

objectinputstream inputstream = new objectinputstream(new bytearrayinputstream(buf));

return inputstream.readobject();

} catch (ioexception e) {

throw new illegalargumentexception(e);

} catch (classnotfoundexception e) {

* @see com.ibatis.sqlmap.client.extensions.typehandlercallback#setparameter(com.ibatis.sqlmap.client.extensions.

* parametersetter, java.lang.object)

public void setparameter(parametersetter paramparametersetter, object paramobject) throws sqlexception {

if (paramobject == null) {

paramparametersetter.setnull(types.blob);

bytearrayoutputstream bytestream = new bytearrayoutputstream();

objectoutputstream objectoutputstream = new objectoutputstream(bytestream);

objectoutputstream.writeobject(paramobject);

paramparametersetter.setbytes(bytestream.tobytearray());

不過接口中的valueof方法,到底是幹什麼用的,什麼時候調用的還沒搞清楚。将這個類配置在sqlmap的resultmap或sql中内聯,都能夠正常的對對象進行存取。

轉載自:https://coolex.info/blog/330.html