2017-01-07 1 views
0

Я новичок в Mybatis. Недавно я использовал собственный универсальный типHander, когда свойство bean совпадает с именем столбца таблицы, select будет вызывать ClassCastException.Mybatis при использовании настраиваемого универсального манипулятора типа и имени свойства компонента и столбца таблицы одинаковы, select повысит ClassCastException

Ниже приведены конфигурацию

mybatis-configuration.xml

<typeHandlers> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.WhetherTypeEnum" jdbcType="CHAR"/> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.SexTypeEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.ArticleTypeEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.EducationLevelEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.ServiceLevelEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.ServiceTypeEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.StaffLevelEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.ArticleStatusEnum" jdbcType="CHAR" /> 
     <typeHandler handler="com.sut.util.enumerate.mybatis.GenericEnumUserType" 
      javaType="com.sut.util.meta.HealthyStatusEnum" jdbcType="CHAR" /> 
</typeHandlers> 

staffMapper.xml

<resultMap type="com.sut.persist.entity.Staff" id="staff"> 
    <id property="id" javaType="int" column="id" /> 
    <result property="staffName" javaType="String" column="STAFF_NAME" /> 
    <result property="imgPath" javaType="String" column="IMG_PATH" /> 
    <result property="staffLevel" javaType="com.sut.util.meta.StaffLevelEnum" column="LEVEL" 
     typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" jdbcType="CHAR"/> 
    <result property="birthDate" javaType="java.util.Date" column="BIRTH_DATE" /> 
    <result property="address" javaType="String" column="address" /> 
    <result property="healthyStatus" javaType="com.sut.util.meta.HealthyStatusEnum" column="HEALTHY_STATUS" 
     typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" jdbcType="CHAR" /> 
    <result property="education" column="education" typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" /> 
    <result property="workYears" javaType="integer" column="WORK_YEARS" /> 
    <result property="selfIntroduction" javaType="String" column="SELF_INTRODUCTION" /> 
    <result property="cert" javaType="String" column="CERT" /> 
    <result property="remark" javaType="String" column="REMARK" /> 
    <result property="serviceType" javaType="com.sut.util.meta.ServiceTypeEnum" column="SERVICE_TYPE" 
     typeHandler="com.sut.util.enumerate.mybatis.GenericEnumUserType" /> 
    <result property="mobile" javaType="String" column="MOBILE" /> 
    <result property="qqNumber" javaType="String" column="QQ_NUMBER" /> 
    <result property="webchatNumber" javaType="String" column="WEBCHAT_NUMBER" /> 
    <result property="webchatQrcode" javaType="String" column="WEBCHAT_QRCODE" /> 
</resultMap> 

<!-- query user by id --> 
<select id="getById" parameterType="long" resultMap="staff"> 
    select 
     staff_id, 
     staff_name, 
     img_path, 
     level as staffLevel, 
     birth_date, 
     address, 
     healthy_status as healthyStatus, 
     education as education, 
     work_years, 
     self_introduction, 
     cert, 
     remark, 
     service_type as serviceType, 
     mobile, 
     qq_number, 
     webchat_number, 
     webchat_qrcode 
    from bbs_staff where staff_id = #{id} 

Staff.java:

public class Staff implements java.io.Serializable { 

    private static final long serialVersionUID = 1L; 

    private long id; 
    private String staffName; 
    private String imgPath; 
    private StaffLevelEnum staffLevel; 
    private java.util.Date birthDate; 
    private java.lang.String address; 
    private HealthyStatusEnum healthyStatus; 
    private EducationLevelEnum educationLevel; 
    private int workYears; 
    private String selfIntroduction; 
    private String cert; 
    private String remark; 
    private ServiceTypeEnum serviceType; 
    private String mobile; 
    private String qqNumber; 
    private String webchatNumber; 
    private String webchatQrcode; 

    /** 
    * default Constructor 
    */ 
    public Staff() { 
     super(); 
    } 


    public long getId() { 
     return id; 
    } 


    public void setId(long id) { 
     this.id = id; 
    } 


    public String getStaffName() { 
     return staffName; 
    } 

    public void setStaffName(String staffName) { 
     this.staffName = staffName; 
    } 

    public String getImgPath() { 
     return imgPath; 
    } 

    public void setImgPath(String imgPath) { 
     this.imgPath = imgPath; 
    } 


    public StaffLevelEnum getStaffLevel() { 
     return staffLevel; 
    } 


    public void setStaffLevel(StaffLevelEnum staffLevel) { 
     this.staffLevel = staffLevel; 
    } 


    public java.util.Date getBirthDate() { 
     return birthDate; 
    } 

    public void setBirthDate(java.util.Date birthDate) { 
     this.birthDate = birthDate; 
    } 

    public java.lang.String getAddress() { 
     return address; 
    } 

    public void setAddress(java.lang.String address) { 
     this.address = address; 
    } 

    public HealthyStatusEnum getHealthyStatus() { 
     return healthyStatus; 
    } 

    public void setHealthyStatus(HealthyStatusEnum healthyStatus) { 
     this.healthyStatus = healthyStatus; 
    } 

    public EducationLevelEnum getEducationLevel() { 
     return educationLevel; 
    } 


    public void setEducationLevel(EducationLevelEnum educationLevel) { 
     this.educationLevel = educationLevel; 
    } 

    public int getWorkYears() { 
     return workYears; 
    } 

    public void setWorkYears(int workYears) { 
     this.workYears = workYears; 
    } 


    public String getSelfIntroduction() { 
     return selfIntroduction; 
    } 


    public void setSelfIntroduction(String selfIntroduction) { 
     this.selfIntroduction = selfIntroduction; 
    } 

    public String getCert() { 
     return cert; 
    } 

    public void setCert(String cert) { 
     this.cert = cert; 
    } 

    public String getRemark() { 
     return remark; 
    } 

    public void setRemark(String remark) { 
     this.remark = remark; 
    } 

    public ServiceTypeEnum getServiceType() { 
     return serviceType; 
    } 

    public void setServiceType(ServiceTypeEnum serviceType) { 
     this.serviceType = serviceType; 
    } 

    public String getMobile() { 
     return mobile; 
    } 

    public void setMobile(String mobile) { 
     this.mobile = mobile; 
    } 

    public String getQqNumber() { 
     return qqNumber; 
    } 

    public void setQqNumber(String qqNumber) { 
     this.qqNumber = qqNumber; 
    } 

    public String getWebchatNumber() { 
     return webchatNumber; 
    } 

    public void setWebchatNumber(String webchatNumber) { 
     this.webchatNumber = webchatNumber; 
    } 

    public String getWebchatQrcode() { 
     return webchatQrcode; 
    } 

    public void setWebchatQrcode(String webchatQrcode) { 
     this.webchatQrcode = webchatQrcode; 
    } 

    @Override 
    public String toString() { 
     return MoreObjects.toStringHelper(Staff.class) 
       .add("id", id) 
       .add("staffName", staffName) 
       .add("imgPath", imgPath) 
       .add("level", staffLevel) 
       .add("birthDate", birthDate) 
       .add("address", address) 
       .add("healthyStatus", healthyStatus) 
       .add("education", educationLevel) 
       .add("workYears", workYears) 
       .add("selfIntroduction", selfIntroduction) 
       .add("cert", cert) 
       .add("remark", remark) 
       .add("serviceType", serviceType) 
       .add("mobile", mobile) 
       .add("qqNumber", qqNumber) 
       .add("webChatNumber", webchatNumber) 
       .add("webChatQrcode", webchatQrcode) 
       .toString(); 
    } 

} 

com.sut.util.enumerate.mybatis.GenericEnumUserType:

public class GenericEnumUserType<E extends StringEnumTypeImp> extends BaseTypeHandler<E>{ 

    private static final Logger LOG = LoggerFactory.getLogger(GenericEnumUserType.class); 

    //mybatis will pass actual class when constructing TypeHandler 
    private Class<E> type; 

    private static final String fromStringCode = "fromStringCode"; 

    public GenericEnumUserType(Class<E> type){ 
     Preconditions.checkNotNull(type, "Type argument cannot be null"); 
     this.type = type; 
    } 

    /** 
    * @see org.apache.ibatis.type.BaseTypeHandler#setNonNullParameter(java.sql.PreparedStatement, int, java.lang.Object, org.apache.ibatis.type.JdbcType) 
    */ 
    @Override 
    public void setNonNullParameter(PreparedStatement ps, int i, StringEnumTypeImp parameter, JdbcType jdbcType) throws SQLException { 
     ps.setString(i, parameter.getStoreValue()); 
    } 

    /** 
    * getResult and use reflect 
    * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String) 
    */ 
    @Override 
    @SuppressWarnings("unchecked") 
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException { 
     LOG.info("return type is : {}", type); 
     String storeValue = rs.getString(columnName); 
     Preconditions.checkNotNull(type, "Type argument cannot be null"); 
     try { 
      Method fromMethod = type.getMethod(fromStringCode, String.class); 
      return (E) fromMethod.invoke(null, storeValue); 
     } catch (IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    /** 
    * 
    * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, int) 
    */ 
    @SuppressWarnings("unchecked") 
    @Override 
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 
     LOG.info("return type is {}", type); 
     String storeValue = rs.getString(columnIndex); 
     Preconditions.checkNotNull(type, "Type argument cannot be null"); 
     try { 
      Method fromMethod = type.getMethod(fromStringCode, String.class); 
      return (E) fromMethod.invoke(null, storeValue); 
     } catch (IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    /** 
    * not used 
    * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.CallableStatement, int) 
    */ 
    @Override 
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 
     try { 
      return type.newInstance(); 
     } catch (InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

} 

при вызове метода GetByID, он поднимет исключение:

Struts has detected an unhandled exception: 

Messages: 
[email protected] 
Could not set property 'education' of 'class com.sut.persist.entity.Staff' with value '[email protected]' Cause: java.lang.IllegalArgumentException: [email protected] 
nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'education' of 'class com.sut.persist.entity.Staff' with value '[email protected]' Cause: java.lang.IllegalArgumentException: [email protected] 

В mybatis документы указанного при использовании Generic TypeHandler , он будет получать по JavaType, даже если jdbcType имеет значение null, он получит правильный TypeHandler. Я три раза проверял конфигурации и отлаживал исходный код. Затем я выясню, что ResultSetWrapper разделит столбцы на mappedColumns и UnmappedColumns, unmappedColumns вернет правильный TypeHandler, поскольку mappedColumns не будет. Мне любопытно, почему это происходит. Является ли это ошибкой или мои настройки неверны.

Среды:
Mybatis: 3.4.1
MySQL: 5,6

Любая помощь будет оценен по достоинству!

+0

Привет, добро пожаловать в Stackoverflo ш. Не могли бы вы также указать реализацию com.sut.util.enumerate.mybatis.GenericEnumUserType? – hakamairi

+0

Благодарим за сообщение. Я добавил код GenericEnumUserType .. –

+0

Не могли бы вы также добавить класс Staff? – hakamairi

ответ

0

В вашей фактической mapper.xml вы можете попробовать сделать следующее для перечисления типов обрабатываемых

<result property="educationLevel" column="education" javaType="com.sut.util.meta.EducationLevelEnum" jdbcType="CHAR" /> 
  • матч на имя свойства от вас POJO educationLevel вместо образования
  • обеспечивают javaType и jdbcType
  • удалить обработчик из отображения результата (пусть mybatis это сделать)
+0

Это действительно работало !! Но я не могу понять, почему –

+0

Вы зарегистрировали обработчики с myBatis для конкретной пары java и jdbc. Теперь, что происходит, основываясь на этих типах, myBatis просматривает обработчик, я предполагаю, что вы можете пропустить тип jdbc, он просто будет искать тип java из реального POJO, но он должен сделать это сам по себе. Это было бы важно для создания фактического обработчика - там, где в конструкторе должен быть указан соответствующий тип Enum. – hakamairi

+0

Вы правы, возможно, это правильный способ использования настраиваемого манипулятора типа в методе resultMapping. Спасибо за вашу помощь –

Смежные вопросы