티스토리 뷰

반응형

발 환경

  • Spring Boot: 3.5.0
  • Spring Batch: 5.2.2
  • Java: 21

문제 상황

Spring Batch Job을 실행할 때 아래와 같은 JSON 문자열을 파라미터로 전달하고 싶었습니다.

{
  "myType": "MY_TYPE_VALUE",
  "myArray": [
    {
      "key": {"id": "001", "category": "MY_CATEGORY_VALUE"},
      "param": {"foo": "002", "bar": "sampleValue"}
    }
  ]
}

하지만 일반적인 방식으로 전달하면 다음과 같은 에러가 발생했습니다:

JobParametersConversionException: Unable to parse job parameter

 

왜 JSON 전달이 안 될까?

DefaultJobParametersConverter의 한계

Spring Batch의 DefaultJobParametersConverter는 다음과 같은 형식으로 파라미터를 파싱합니다:

paramKey=value,type

예를 들어:

count=100,long
name=test,string

 

문제는 JSON에도 , (쉼표)가 있다는 것입니다!

{"name":"test","age":30}
        ↑ 이 쉼표를 타입 구분자로 인식!

 

Spring Batch의 JsonJobParametersConverter (이거 안씀 주의)

Spring Batch 5.x부터 org.springframework.batch.core.converter.JsonJobParametersConverter가 제공됩니다.하지만 이것은 제가 원하는 방식과 차이가 있었는데:

Spring Batch JsonJobParametersConverter는 JobParameters 전체를 JSON으로 직렬화/역직렬화하는 용도입니다.

{
  "paramName": {
    "value": "actualValue",
    "type": "java.lang.String",
    "identifying": true
  }
}

 

이를 위해서 기존 파라미터를 value, type을 명시하고, 다시 한번 이를 문자열 형식으로 escape 시켜야 하므로 파라미터 생김새가 지나치게 복잡한 문제가 있었습니다.

 

해결 방법: 커스텀 Converter

Json 형식의 파라미터를 구분하고 무조건 String 타입으로 처리하는, 즉 쉼표 파싱을 건너뛰는 커스텀 컨버터를 구현합니다.

예시 코드에서는 'JsonStr' 으로 끝나는 프로퍼티를 String 타입으로 판단하도록 했습니다.  

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * Json 형식 문자열 파라미터를 String으로 인식하기 위한 커스텀 JobParametersConverter
 * 
 * DefaultJobParametersConverter 구현상 ',' 로 value와 type을 구분하는데
 * JSON은 구조상 ','가 있어서 별도 처리가 필요함
 * 
 * JsonStr로 끝나는 모든 프로퍼티는 자동으로 String으로 등록됩니다.
 * 예: batchRequestJsonStr -> batchRequestJsonStr (String 타입)
 */
@Component
public class JsonStringAvailableJobParametersConverter extends DefaultJobParametersConverter {

    private static final String JSON_STR_SUFFIX = "JsonStr";

    @Override
    public @NonNull JobParameters getJobParameters(@Nullable Properties properties) {
        if (properties == null || properties.isEmpty()) {
            return super.getJobParameters(properties);
        }

        // JsonStr로 끝나는 프로퍼티와 아닌 프로퍼티 분리
        Properties jsonStrProperties = new Properties();
        Properties otherProperties = new Properties();
        
        for (String key : properties.stringPropertyNames()) {
            if (key.endsWith(JSON_STR_SUFFIX)) {
                jsonStrProperties.setProperty(key, properties.getProperty(key));
            } else {
                otherProperties.setProperty(key, properties.getProperty(key));
            }
        }

        // 다른 Properties는 DefaultJobParametersConverter에 위임
        JobParameters baseParams = super.getJobParameters(otherProperties);
        
        // JsonStr로 끝나는 프로퍼티들을 String으로 추가
        JobParametersBuilder builder = new JobParametersBuilder(baseParams);
        for (String key : jsonStrProperties.stringPropertyNames()) {
            String value = jsonStrProperties.getProperty(key);
            builder.addString(key, value);
        }

        return builder.toJobParameters();
    }
}

 

커스텀 Converter를 Bean으로 등록하고 사용처에서 아래와 같이 사용합니다.

@Value("#{jobParameters['batchRequestJsonStr']}")

 

배치 실행시 문자열 전송을 위해서 escape 처리는 필요합니다

--spring.batch.job.name=myBatchJob
batchRequestJsonStr={\"myType\":\"MY_TYPE_VALUE\",\"myArray\":[{\"key\":{\"id\":\"001\",\"category\":\"MY_CATEGORY_VALUE\"},\"param\":{\"foo\":\"002\",\"bar\":\"sampleValue\"}}]}

장점

  • 복잡한 JSON 객체를 파라미터로 전달 가능
  • 기존 파라미터 처리 방식은 그대로 유지
  • 확장 가능: 여러 JSON 파라미터 추가 가능
  • 명시적: 'JsonStr' 접미사로 의도 표현

 

 

반응형
댓글