mybatis-3
mybatis-3 copied to clipboard
MyBatis is ignoring setting of typeHandler in @Result annotation in Mapper
MyBatis version
3.4.1
Database vendor and version
Informix IBM 12.10, ifxjdbc 4.10.10
Test case or example project
In TEXT columns of two tables in database we have the encoding of UTF-8 instead of normal commonly used in our application Latin2 (ISO-8559-2). To handle encoding of values in that columns we had to write some extra code after selecting object from database to map String from Latin2 to UTF-8. It is working but I decided to write TypeHandler to handle situation like this and use it when we need to, without getting to remember about some extra code.
I wrote UTF8TextTypeHandler that looks like that:
public class UTF8TextTypeHandler extends BaseTypeHandler<String> {
static final String DATABASE_CHARSET = "ISO-8859-2";
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
byte[] byteParameter = s.getBytes(Charset.forName(DATABASE_CHARSET));
ByteArrayInputStream bis = new ByteArrayInputStream(byteParameter);
preparedStatement.setBinaryStream(i, bis, byteParameter.length);
}
@Override
public String getNullableResult(ResultSet resultSet, String s) throws SQLException {
return returnUTF8String(resultSet.getBlob(s));
}
@Override
public String getNullableResult(ResultSet resultSet, int i) throws SQLException {
return returnUTF8String(resultSet.getBlob(i));
}
@Override
public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return returnUTF8String(callableStatement.getBlob(i));
}
private String returnUTF8String(Blob blob) throws SQLException {
byte[] returnValue = null;
if (nonNull(blob)) {
returnValue = blob.getBytes(1, (int) blob.length());
}
return new String(returnValue, StandardCharsets.UTF_8);
}
}
And added configuration to generatorConfig.xml
to one of the tables:
<table tableName="messages" domainObjectName="Message" mapperName="MessageMapper"
sqlProviderName="MessageSqlProvider">
<columnOverride column="body" property="body" typeHandler="xxx.UTF8TextTypeHandler"/>
</table>
After generating code I have properly working example for messages table - when I debug my UTF8TextTypeHandler is getting executed and String in good coding is returned.
We have a select that is not connected with a generated object because it is using some external system table and we don't want to map it cause we use it only once.
We have a select that looks like that:
@Select({
"SELECT LIMIT 1 n.kom_body as n_kom_body FROM table1 kn, table2 n, table3 k",
"WHERE kn.reference = k.id AND k.id_out = n.id_out AND kn.id = #{id, jdbcType=INTEGER}"
})
@Results({
@Result(column="n_kom_body", property="n_kom_body", typeHandler=UTF8TextTypeHandler.class, jdbcType=JdbcType.CLOB)
})
String selectMessageContent(Integer id);
It is made similar to that I had generated by generator in first case:
@SelectProvider(type=MbgMessageSqlProvider.class, method="selectByFilterWithBLOBs")
@Results({
@Result(column="id", property="id", jdbcType=JdbcType.INTEGER),
@Result(column="body", property="body", typeHandler=UTF8TextTypeHandler.class, jdbcType=JdbcType.CLOB)
})
List<Message> selectByFilterWithBLOBs(MessageFilter filter);
And in first case it is using the UTF8TextTypeHandler when selecting data, in second when we have select that is written "by hand" that is using StringTypeHandler (checked in debug). I don't understand it why it's not using provided typeHandler.
My mybatis config looks like that:
<typeHandlers>
<typeHandler javaType="string" jdbcType="LONGVARCHAR" handler="org.apache.ibatis.type.StringTypeHandler" />
<typeHandler handler="xxx.CaGetValueTypeHandler"/>
<typeHandler handler="xxx.CaEnumNameTypeHandler"/>
</typeHandlers>
If I add new typeHandler above the overriding default for LONGVARCHAR it works for two but it doesn't really answer my issue.
Why in select - selectByFilterWithBLOBs it works like a charm and using UTF8TextTypeHandler and in selectMessageContent it is using StringTypeHandler?
Expected result
selectByFilterWithBLOBs and selectMessageContent should use UTF8TextTypeHandler if that handler is provided in @Result annotation
Actual result
selectByFilterWithBLOBs is using UTF8TextTypeHandler and selectMessageContent is using StringTypeHandler.
the method get typeHandler from typeHandlerRegistry, not from you pointed out in resultMap. so when you use <typeHandlers>
, it works. But the one from your pointed out, the other from typeHandlerRegistry.
according the doc : specify a mapping definition for the property. Maybe @Result
is used only for the property of returnObject, not the returnObject.