개발/Java,Spring

SpringBoot Batch에서 JobParameter로 받을 수 있는 Type

호돌맨 2019. 5. 17. 12:40

개요

SpringBoot Batch에서 JobParameter로 받을 수 있는 타입에 대하여 이야기 합니다.

이슈

SpringBoot Batch 실행 시 JobParameter로 받을 수 있는 타입은 한정되어 있다. String, Boolean, Integer, Date. 하지만 지금은 2019년.. Date는 상당히 골치아프다. 나는 LocalDate를 사용하고 싶었다. 그래서 아래와 같이 JobParameter를 받아줄 수 있는 Class를 만들었다.

public class MyJobParameter {
    @Value("#{jobParameters[requestDate]}")
    private LocalDate requestDate;

    public void setRequestDate(String requestDate) {
        this.requestDate = parse(requestDate);
    }
}

public class MyBatchConfiguration {
    @Bean
    public void myJobParameter() {
        return new MyJobParameter();
    }
}

그리고 필요한 Batch코드에서 Bean으로 만들어주면 사용이 가능할거라 생각했다.
그런데 에러가 발생했다.

Cannot convert value of type 'java.lang.String' to required type '... LocalDate': no matching editors or conversion strategy found

나는 setter method(setRequestDate(..))가 있으면 당연히 그 부분을 통해 주입 될거라 생각했다.
왜냐하면 enum 타입은 아래와같이 잘 사용 해왔기 때문이다.

public class MyJobParameter {
    @Value("#{jobParameters[type]}")
    private MyEnum type;

    public void setType(String type) {
        this.type = MyEnum.valueOf(type);
    }
}

결론적으로 어느 코드도 setter method는 호출되지 않는다.

jobParameter가 String, Boolean, Integer, Date형태라면 DefaultJobParametersConverter.java에서 convert후 데이터를 cache한다. 하지만 type detect에 실패하면 BeanAnnotationProcessor통해 주입 되는데 TypeConverterSupport.java에서 convertIfNecessary method를 통해 변환을 한다. (내부적으로 변환이 되면 쓰는거고 아니면 exception 터지는 거고..)

그러니깐 내부적으로 Enum은 변환을 해주기 때문에 지금까지 사용이 가능한거였고 LocalDate는 변환이 안되서 사용이 불가능 했던 것이다. setter method를 참조 할거라는건 내 착각이었다.

하지만 @Value annotation을 setter method에 작성하면 주입이 가능하다.

@Value("#{jobParameters[type]}")
public void setType(String type) {
    this.type = MyEnum.valueOf(type);
}

물론 이를 응용한다면 LocalDate도 주입이 가능할거다.
그렇다면 convertIfNecessary에서 변환해줄 수 있는 타입의 조건은 무엇일까? 귀찮아서 소스를 전체적으로 파악하지는 못했지만 테스트 결과 String constructor가 있으면 사용할 수 있다는걸 알았다.

public class MyValue {
    private final String value;
    public MyValue(String value) {
        this.value = value;
    }
}

public class MyJobParameter {
    @Value("#{jobParameters[value]}")
    private MyValue value;
}

이렇게 하면 Custom Class(?)의 타입을 사용할 수 있다. 하지만 저걸 위해서 LocalDate를 상속받아 방법 해버리는건 매우 번거로운 일이다. 심지어 LocalDate는 final Class이기 때문에 상속할수도 없고..

그냥 이 정도는 setter method를 사용해서 해결 해야겠다.

요약

  1. job parameter로 사용할 수 있는 타입은 String, Boolean, Integer, Date
  2. Enum도 가능함.
  3. String constructor가 있는 Class도 가능함
  4. LocalDate같은건 setter method를 통해 injection 받도록 하자.