상세 컨텐츠

본문 제목

[mybatis] NumberformatException이 나는 경우

Programing/Java

by 호짱 HoZang 2019. 7. 12. 01:09

본문

java.lang.NumberFormatException: 해결방법

### Error querying database. Cause: java.lang.NumberFormatException: For input string: “a”
### Cause: java.lang.NumberFormatException: For input string: “a”

myBatis 사용시 위와 같은 에러가 발생하는 경우가 있다.

원인을 살펴보면 다음과 같은 형식의 문자열 비교 구문에서 에러가 발생하는 것을 확인할 수 있다.

분명 문자열 비교 구문인데 NumberFormatException이 발생하는 상황이다.

결론적으로 위 현상은 myBatis 문제는 아니고 OGNL(Object Graph Navigation Language) 의 문제이다.

OGNL 인터프리터에서는 위 구문의 ‘Y’를 char 형으로 인식하고, ‘YY’나 “Y”는 String으로 인식한다. (따옴표를 잘보자)

그래서 <if test=”stringValue == ‘Y’”> 이와 같은 구문을 비교할 때  NumberFormat으로 비교를 시도하여 Exception이 발생한다.

이유는 java의 char형은 실제로 문자의 코드값을 저장하기 때문이다. 그래서 아래와 같은 형변환이 가능하다.

그래서 위와 같은 상황을 피하기 위해서는 다음과 같은 해결책이 존재한다.

1. <if test=’stringValue == “Y”‘> – 쌍따옴표와 홑따옴표의 위치를 변경

2. <if test=”stringValue == &quot;Y&quot;”> – 쌍따옴표를 HTML 코드로 변경

3. <if test=”stringValue == ‘Y’.toString()”> – toString() 함수를 사용해 String 형으로 변환

개인적으로는 1번 방법이 제일 깔끔하고 코드 읽기도 쉬운거 같아서 if 구문이 들어간 곳에 전부 적용해서 쓰고 있다

요새 MyBatis를 자주 쓰다보니 나쁜 프로그래밍 습관때문에 자주 만나는 오류가 하나 있습니다.

해당 오류가 나는 객체는 다음과 같은 객체입니다.

INFO  CommonRequestInterceptor - [CommonRequestInterceptor] AdminCategoryCodeController.categoryCodeGrid() 기능 실행

11월 09, 2015 11:25:02 오전 org.apache.catalina.core.StandardWrapperValve invoke

심각: Servlet.service() for servlet [dispatcherServlet] in context with path [/kosbiDB] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 

### Error querying database.  Cause: java.lang.NumberFormatException: For input string: "Y"

### Cause: java.lang.NumberFormatException: For input string: "Y"] with root cause

java.lang.NumberFormatException: For input string: "Y"

    at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

 

public class DocumentCategoryCode extends BasicSearchParameterModel implements BasicGridTemplate {



    /**

     * Auto-Generated

     */

    private static final long serialVersionUID = 8297329412255195696L;

    private String documentTypeCode;

    private String documentTypeName;

    private String documentTypeUseYN;

    

    private String webZineCategory;    //    웹진만 검색할때 사용하는 Search Parameter

그리고 오류가 나는 MyBatis 표현 Query 부분은 다음이죠.

<?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="res.kosbi.code.mapper.CategoryCodeMapper">

    

    <select id="dgrant_getCategoryCodeListForGrid"

        parameterType="res.kosbi.code.model.DocumentCategoryCode"

        resultType="res.kosbi.code.model.DocumentCategoryCode"

    >

        /* [dgrant_getCategoryCodeListForGrid] 코드조회 / 김덕선 / 2015-11-04    */

        SELECT *

          FROM

               (SELECT ROWNUM AS RNUM,

                      A.*

                 FROM

                      (

                <!-- 본 쿼리 -->        

                    SELECT DOCTYPE_CODE AS documentTypeCode,

                           DOCTYPE_NAME AS documentTypeName,

                           DOCTYPE_USE_YN AS documentTypeUseYN

                      FROM TB_DOCTYPE

                      WHERE 1=1

                      <if test="documentTypeUseYN != null and documentTypeUseYN != '' and documentTypeUseYN != 'all'">

                          AND DOCTYPE_USE_YN = #{documentTypeUseYN}

                      </if>

                    <if test="webZineCategory == 'Y'">

                          AND LENGTH(TRIM(DOCTYPE_CODE)) <![CDATA[>=]]> 4 

                      </if>

 

맨 아래 25번 라인 근처에 있는 webZineCategory에서 해당 에러가 납니다.

겉으로 보기에는 정상적인 코드인데 왜일까요?

1. 꼼꼼한 MyBatis의 Type 정의

겉으로 볼때에는 String형인 webZineCategory 변수에 대해서 String으로 보이는 'Y'와 비교한 것인데,

MyBatis에서는 NumberFormatException이 뜨면서 이 값을 숫자로 인식하려고 합니다.

그렇기 때문에 오류가 나고 있습니다.

이 이유는 간단합니다. MyBatis가 'Y'라는 문자열을 C의 char와 같이 취급하고 있기 때문이죠.

MyBatis는 'YYY' 같이 안에 charSequence가 있으면 해당 Object를 String으로, 'Y' 같이 한자만 있으면 이를 Character로 인식합니다.

그래서 char 형인 'Y'와 String을 비교하려 하니, format을 변경하는데에서 오류가 나는 것이죠.

같은 이유로, 위의 documentTypeUseYN = 'all'인 부분에서는 둘 다 String으로 인식하기 때문에 오류가 나지 않습니다.

참으로 헷깔리기 쉬운 MyBatis의 형변환 규칙이죠. ^^

2. 올바른 MyBatis에서의 표현법

따라서 이러한 문제점을 해결하기 위해서는 해당 상수들에 대하여 엄격하게 String임을 선언해 주는 것이 필요합니다.

이 방법은 간단합니다. 바로 " (쌍따옴표)를 활용하는 것이죠.

이에 맞춰서 위의 XML을 바꾸면 다음과 같이 바꾸면 됩니다.

<?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="res.kosbi.code.mapper.CategoryCodeMapper">

    

    <select id="dgrant_getCategoryCodeListForGrid"

        parameterType="res.kosbi.code.model.DocumentCategoryCode"

        resultType="res.kosbi.code.model.DocumentCategoryCode"

    >

        /* [dgrant_getCategoryCodeListForGrid] 코드조회 / 김덕선 / 2015-11-04    */

        SELECT *

          FROM

               (SELECT ROWNUM AS RNUM,

                      A.*

                 FROM

                      (

                <!-- 본 쿼리 -->        

                    SELECT DOCTYPE_CODE AS documentTypeCode,

                           DOCTYPE_NAME AS documentTypeName,

                           DOCTYPE_USE_YN AS documentTypeUseYN

                      FROM TB_DOCTYPE

                      WHERE 1=1

                      <if test='documentTypeUseYN != null and documentTypeUseYN != "" and documentTypeUseYN != "all"'>

                          AND DOCTYPE_USE_YN = #{documentTypeUseYN}

                      </if>

                    <if test='webZineCategory == "Y"'>

                          AND LENGTH(TRIM(DOCTYPE_CODE)) <![CDATA[>=]]> 4 

                      </if>

따라서 쌍따옴표와 작은따옴표를 혼용할 경우 그 구분을 확실하게 하는것이 중요합니다.

이런 경우는 MyBatis 뿐만 아니라 Javascript에서도 발생할 수 있는 문제이니까요.

저도 이 규칙을 꼭 기억해야 하는데...... 자주 까먹네요. ^^ 그래서 정리합니다.

관련글 더보기

댓글 영역