None of mybatis typehandler getResult is entered

283 Views Asked by At

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

0

There are 0 best solutions below