I think I'm seeking for trouble for myself using complex structure but I need to get over this problem. I have object nested in object, then the object list Here's the base Entity
@Data
public class BaseEntity {
private Long id;
private String name;
private String description;
}
Here's my impactEntity built on the top of base Entity
@Data
public class ImpactEntity implements Structable{
private String ref;
private String ASOF;
private Long deliverTime;
private String SLAMissed;
private BaseEntity client;
private BaseEntity application;
private BaseEntity deliverable;
}
Here's my real final object:
@Data
public class IncidentEntity {
private String PID;
private String ID;
private String NID;
private String REF;
private String RREF;
private String ASOF;
private Long StartTime;
private Long endTime;
private String description;
private String active;
private Long createAt;
private List<ImpactEntity> impacts;
}
Here's my incidentMapper:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.well.valley.mapper.IncidentMapper" >
<resultMap id="IncidentEntity" type="org.well.valley.entity.IncidentEntity">
<result column="PID" jdbcType="VARCHAR" property="PID" />
<result column="ID" jdbcType="VARCHAR" property="ID" />
<result column="NID" jdbcType="VARCHAR" property="NID" />
<result column="REF" jdbcType="VARCHAR" property="REF" />
<result column="RREF" jdbcType="VARCHAR" property="RREF" />
<result column="ASOF" jdbcType="VARCHAR" property="ASOF" />
<result column="STARTTIME" jdbcType="INTEGER" property="startTime" />
<result column="ENDTIME" jdbcType="INTEGER" property="endTime" />
<result column="DESCRIPTION" jdbcType="VARCHAR" property="description" />
<result column="ACTIVE" jdbcType="VARCHAR" property="active" />
<result column="CREATEAt" jdbcType="INTEGER" property="createAt" />
<result property="impacts" column="IMPACTS" typeHandler="org.well.valley.utils.typehandlers.OracleTypeHandler" />
</resultMap>
<select id="get" statementType="CALLABLE" parameterType="org.well.valley.entity.IncidentEntity">
call get_incidents(
#{ASOF, jdbcType=VARCHAR},
#{ref, jdbcType=VARCHAR},
#{active, jdbcType=VARCHAR},
#{outParam.c1, mode=OUT, jdbcType=CURSOR, javaType=java.sql.ResultSet, resultMap=IncidentEntity}
)
</select>
</mapper>
I'm using a customized typeHandler to deal with
<result property="impacts" column="IMPACTS" typeHandler="org.well.valley.utils.typehandlers.OracleTypeHandler" />
Here's my full body of the OracleTypeHandler. I want to make it very generic and be able to deal with anything, including something like List although I haven't started the code to deal with the List in the resultset yet.
public class OracleTypeHandler<T> extends BaseTypeHandler<T> {
private Logger logger = LoggerFactory.getLogger(getClass());
private ObjectMapper objectMapper = new ObjectMapper();
private DBMapperBean getDBMapperBean() {
return SpringContext.getBean(DBMapperBean.class);
}
private Class<T> type;
protected int getIndex(ResultSetMetaData data, String columnName) throws SQLException {
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>11111111111111111111111111");
for (int i = 1; i <= data.getColumnCount(); i++) {
String c = data.getColumnName(i);
if(columnName.equals(c))
{
return i;
}
}
return -1;
}
public OracleTypeHandler(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
logger.info(">>>>>>>>>>>>>>>>>>>>Type is:{}", type);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int index, T parameter, JdbcType jdbcType)
throws SQLException {
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>333333333333333333333333");
Connection conn = ps.getConnection();
if(parameter.getClass().isArray()) {
if(parameter instanceof String[]) {
Array array = ((OracleConnection) conn).createOracleArray("STRINGARRAY", parameter);
ps.setArray(index, array);
array.free();
}
}
}
@Override
public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>444444444444444444444444444444");
int index = getIndex(metaData, columnName);
String columnClassName = metaData.getColumnClassName(index);
if(columnClassName.equals("oracle.jdbc.OracleStruct"))
{
java.sql.Struct o = (java.sql.Struct)resultSet.getObject(index);
return extractObject(o);
}else if(columnClassName.equals("oracle.jdbc.OracleArray"))
{
Array array = resultSet.getArray(columnName);
Object r = array.getArray();
array.free();
return (T) r;
}
return null;
}
private String typeNameConvert(String type, String target)
{
if(target.equals("DBTYPE"))
{
return type.concat("TYPE");
}else
{
return type.substring(0, type.length()-4);
}
}
private T extractObject(Struct o) throws SQLException {
String typeName = o.getSQLTypeName();
typeName = typeName.substring(typeName.lastIndexOf(".")+1);DBMapperBean dbMapperBean = getDBMapperBean();
typeName = typeNameConvert(typeName, "JAVATYPE");
if(typeName.endsWith("ARRAY"))
{
switch (typeName){
case "STRINGARRAY":
break;
}
}else {
HashMap <String, Class> map = dbMapperBean.getMap();
try {
Class<?> cls = (Class<?>) map.get(typeName);
Structable obj = (Structable) cls.getDeclaredConstructor().newInstance();
Object[] attrs = o.getAttributes();
List<Field> fields = obj.getOrderedField(obj.getClass().getDeclaredFields());
int i = 0;
for (Field f : fields) {
f.setAccessible(true);
Object source = attrs[i];
if(source == null)
{
f.set(obj, null);
}
else {
Class targetType = f.getType();
Class sourceType = source.getClass();
if (Number.class.isAssignableFrom(targetType) && Number.class.isAssignableFrom(sourceType)) {
if (targetType == Long.class) {
source = Long.parseLong(source.toString());
}
}
try {
f.set(obj, source);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
i++;
}
return (T) obj;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>66666666666666666");
Struct struct =(java.sql.Struct) rs.getObject(columnIndex);
return extractObject(struct);
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7777777777777777777");
Struct struct =(java.sql.Struct) cs.getObject(columnIndex);
return extractObject(struct);
}
}
So even before the DB stored procedure is called, the constructor of the OracleTypeHandler is called, which is expected, as it's to build up a List of the object of objects
19:58:28.439 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:class org.well.valley.entity.BaseEntity
19:58:33.692 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:class org.well.valley.entity.BaseEntity
20:02:43.477 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:class org.well.valley.entity.BaseEntity
20:02:47.161 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:class org.well.valley.entity.BaseEntity
20:03:00.370 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:class [Ljava.lang.String;
20:03:16.080 INFO o.w.v.u.t.OracleTypeHandler - >>>>>>>>>>>>>>>>>>>>Type is:interface java.util.List
However, after my DB stored procedure is called, none of the 3 getNullableResult methods in the typehandler is entered, while I would expect for whatever result set is retrieved one of them should be entered. To be more specific I think this one should be entered, as this is the one to retrieve the result using column name. I was expecting to do some job inside this method. However, it's not entered, and returned an empty List(but if I call the procedure in DB directly I got the result)
public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException
So - can someone please advise what's the reason the getNullableResult methods were not entered? Which typehandler Mybatis us in this case to deal with my impactList?
Thanks a million