본문 바로가기

학습/TIL

RequestParam, RequestBody, MyBatis 는 어떻게 객체를 매핑할까?

1. Controller RequestArgument Test

  1. 🚫  NoArgsConstructor
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

b. ✅  ArgsConstructor

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

@AllArgsConstructor
public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

c. ✅  Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

@Setter
public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

d. ✅  ArgsConstructor & Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

		// name2 로 매핑된 데이터가 주입됨
    public void setName2(String name) {
        this.name = name;
    }
}

ArgsConstructor 실행 후 Setter 실행

위의 코드에서 name 이 name2 로 인해 변화

결과 값 name = “a3”

 

e. ✅  NoArgsConstructor & ArgsConstructor & Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(){
        System.out.println("엥");
    }

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

		// name2 로 매핑된 데이터가 주입됨
    public void setName2(String name) {
        this.name = name;
    }
}

NoArgsContructor 실행 후 Setter 실행

 

f. 🚫   ArgsConstructor1 & ArgsConstructor2

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }
}

java.lang.IllegalStateException : No primary or default constructor found for class com.front.test.ConstructTest

한개의 생성자를 사용하거나 기본 생성자를 만들어야 한다고 한다.

💡 결론

NoArgsConstructor ( or ArgsConstructor) & Setter 순으로 실행되며

생성자의 실행 우선순위는 NoArgs 가 없을 시 에 Args 를 실행함

NoArgs 가 없고 생성자가 여러개 일 경우엔 IllegalStateException 발생


2. Controller RequestBody GET

  1. 🚫  NoArgsConstructor
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
	public void test(@RequestBody ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

b. ✅  ArgsConstructor

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(@RequestBody ConstructTest test) {
        System.out.println(test);
    }
}

@AllArgsConstructor
public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

c. ✅  Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(@RequestBody ConstructTest test) {
        System.out.println(test);
    }
}

@Setter
public class ConstructTest {
    private String name;
    private String regCd;
    private String carNo;
}

d. ✅  ArgsConstructor & Setter

  • curl -X GET -H "Content-Type: application/json" \ -d " \ { \ \"name\":\"curl json example\", \ \"name2\": \"test\",\ \"regCd2\": \"a3a3\" }\ " \ http://localhost/test353/
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(@RequestBody ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

		public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

Constructor 에 있는 Argument 를 제외한 필드만 Set 함수를 시행함.

위의 코드에서는 생성자 이후에 setRegCd2, setName2 메서드를 시행함.

 

e. ✅  NoArgsConstructor & ArgsConstructor & Setter

  • curl -X GET -H "Content-Type: application/json" \ -d " \ { \ \"name\":\"curl json example\", \ \"name2\": \"test\",\ \"regCd2\": \"a3a3\" }\ " \ http://localhost/test353/
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(@RequestBody ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(){
        System.out.println("엥");
    }

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

		public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

NoArgsContructor 실행 후 Setter 실행

 

f. 🚫   ArgsConstructor1 & ArgsConstructor2

  • curl -X GET -H "Content-Type: application/json" \ -d " \ { \ \"name\":\"curl json example\", \ \"name2\": \"test\",\ \"regCd2\": \"a3a3\" }\ " \ http://localhost/test353/
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test(ConstructTest test) {
        System.out.println(test);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }

    public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }
}

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.front.test.ConstructTest]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.front.test.ConstructTest (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

이 또한 마찬가지로 한개의 생성자를 사용하거나 기본 생성자를 만들어야 한다고 한다. 예외만 다름

💡 결론

NoArgsConstructor ( or ArgsConstructor) & Setter( Constructor 에 없는 필드 ) 순으로 실행되며

생성자의 실행 우선순위는 NoArgs 가 없을 시 에 Args 를 실행함

NoArgs 가 없고 생성자가 여러개 일 경우엔 HttpMessageConversionException 발생


3. MyBatis ResultType

  1. ✅  NoArgsConstructor
@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS SELL_NO2
		  FROM CAR
     LIMIT 1;
</select>

b. ✅  ArgsConstructor

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS SELL_NO2
		  FROM CAR
     LIMIT 1;
</select>

3개의 필드만 있는 ArgsConstructor 를 작성했음에도 다른 필드값을 채워줌

❓ org.apache.ibatis.executor.resultset 의 DefaultResultSetHandler 를 통해 빈 값을 채우는 듯

 

c. ✅  Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;
		
		public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

    public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS NAME2
		  FROM CAR
     LIMIT 1;
</select>

d. ✅  ArgsConstructor & Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }
		
		public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

    public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS NAME2
		  FROM CAR
     LIMIT 1;
</select>

ArgsConstructor 실행 후 Setter 실행

 

e. ✅  NoArgsConstructor & ArgsConstructor & Setter

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(){
        System.out.println("엥");
    }

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }
		
		public void setName(String name) {
        this.name = name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

    public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS NAME2
		  FROM CAR
     LIMIT 1;
</select>

NoArgsConstructor 실행 후 Setter 실행

 

f. 🚫   ArgsConstructor1 & ArgsConstructor2

@Controller
public class ConstructTestController {

    @GetMapping(value = "/test353")
    public void test() {
        ConstructTest constructTest = mapper.selectTest();
        System.out.println(constructTest);
    }
}

public class ConstructTest {
    private String name;
    private Integer mileage;
    private String regCd;
    private String carNo;
    private String name2;

		public ConstructTest(String name, Integer mileage, String regCd) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
    }

		public ConstructTest(String name, Integer mileage, String regCd, String carNo) {
        this.name = name;
        this.mileage = mileage;
        this.regCd = regCd;
        this.carNo = carNo;
    }
		
		public void setName(String name) {
        this.name= name;
    }

    public void setMileage(Integer mileage) {
        this.mileage = mileage;
    }

    public void setRegCd(String regCd) {
        this.regCd = regCd;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public void setName2(String name) {
        this.name = name;
    }

    public void setRegCd2(String regCd){
        System.out.println(regCd);
    }
}

<select id="selectTest" resultType="com.front.test.ConstructTest">
		SELECT
		       NAME
		     , MILEAGE
		     , REG_CD
		     , CAR_NO
		     , 'a' AS NAME2
		  FROM CAR
     LIMIT 1;
</select>

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.front.test.ConstructTest matching [java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String]

이 또한 마찬가지로 한개의 생성자를 사용하거나 기본 생성자를 만들어야 한다고 한다. 예외만 다름

💡 결론

NoArgsConstructor ( or ArgsConstructor) & Setter 순으로 실행되며

생성자의 실행 우선순위는 NoArgs 가 없을 시 에 Args 를 실행함

NoArgs 가 없고 생성자가 여러개 일 경우엔 MyBatisSystemException 발생

'학습 > TIL' 카테고리의 다른 글

Spring boot Pageable 유지하며 Restrict Sort 구현하기  (0) 2024.05.09