개발/Database

[myBatis] select시 NoSuchMethodException , <init>() error

신매력 2015. 4. 24. 19:01

mybatis에서 select문을 실행시킬 때 객체에 저장하는 과정에서 

아래와 같은 에러가 발생했다.


error:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Error instantiating class 클래스명 with invalid types () or values (). Cause: java.lang.NoSuchMethodException: 클래스명<init>()



select 결과를 저장하는 클래스는 아래와 같은 형식이었다.


public class Test {

   private int a;

   private int b;


   public Test(int a, int b) {

      this.a = a;

      this.b = b;

   }

   // getter, setter..

} 


파라미터가 있는 생성자가 있으면서

default 생성자가 없는 클래스였던거다.


파라미터 있는 생성자를 만들 때는 default constructor를 만드는 것을 권장한다는 말을 들었는데도

안만들었던 이유는

Test 클래스를 만들 때는 반드시 a, b 파라미터가 생성시부터 항상 존재하게 하려는 의도로 만든 것이었다.



에러가 뜨자마자 default constructor가 없어서 나는 에러임을 감지했지만,

다른 방법이 있지 않을까 해서 mybatis가 select한 후 객체에 저장하는 부분을 찾아봤다.


mybtis가 자바의 reflection을 이용해서, 저장할 인스턴스를 생성시키고, 매핑을 시켜주는데.

그 때 ObjectFactory 라는 클래스를 이용한다.

create 메소드가 두개 있는데 하나는 기본 생성자 처리,

또 하나는 파라미터가 있는 생성자 처리이다.

디폴트 생성자가 없으니 인스턴스를 생성하지 못하고 익셉션을 내뱉는 것이다.



그렇다고 공개적인 디폴트 생성자는 만들고 싶지 않았기 때문에,

디폴트 생성자를 호출할 수 없도록 private으로 만들고

인스턴스를 생성시켜주는 용도의 static 메소드를 하나 만들어서 사용해서 해결했다.

(앞으로 파라미터 있는 생성자를 만들 때는 반드시 디폴트 생성자를 생성할 것)


public class Test {

   private int a;

   private int b;


   private Test() {} // 디폴트 생성자


   // 인스턴스 생성 메소드

   public static Test createInstance(int a, int b) {

      Test test = new Test();

      test.a = a;

      test.b = b;

      return test;

   }

   // getter, setter..




그런데 mybatis는 어찌 private으로 되어있는 생성자의 접근이 가능했을까?


마이바티스에서 사용되는 Reflection 클래스에서 

타깃 클래스들의 생성자 접근 옵션을 접근 가능으로 바꾸기 때문이다.

constructor.setAccessible(true);

이렇게 세팅을 하기 때문에 어떠한 접근제한자이더라도 mybatis는 접근할 수 있다.