kagamihogeの日記

kagamihogeの日記です。

spring-batchのJson読み込み

ソースコード

plugins {
    id 'org.springframework.boot' version '2.2.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-batch'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
}

JsonItemReaderを使用してjson読み込みを行う。

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.json.JacksonJsonObjectReader;
import org.springframework.batch.item.json.JsonItemReader;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ResourceLoader;

@SpringBootApplication
@EnableBatchProcessing
public class App {
    @Bean
    public Job job(JobBuilderFactory jobs, StepBuilderFactory steps, ResourceLoader loader) {
        return jobs.get("job").start(step1(steps, loader)).build();
    }

    public Step step1(StepBuilderFactory stepBuilderFactory, ResourceLoader loader) {
        JsonItemReader<JsonItem> reader = new JsonItemReader<JsonItem>(
                loader.getResource("classpath:json/json1.json"),
                new JacksonJsonObjectReader<JsonItem>(JsonItem.class));
        reader.setName("jsonReader");

        return stepBuilderFactory
                .get("step1")
                .<JsonItem, JsonItem>chunk(4)
                .reader(reader)
                .writer(items -> items.forEach(System.out::println))
                .build();
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(App.class).run(args);
    }
}

はまりどころ

Name must be assigned for the sake of defining the execution context keys prefix.

java.lang.IllegalArgumentException: Name must be assigned for the sake of defining the execution context keys prefix.
    at org.springframework.util.Assert.hasText(Assert.java:284) ~[spring-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.batch.item.util.ExecutionContextUserSupport.getKey(ExecutionContextUserSupport.java:62) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.item.ItemStreamSupport.getExecutionContextKey(ItemStreamSupport.java:71) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]

ItemStreamSupport.setNameで適当な名前を指定しないと上記の例外がスローされる。

JsonItemReaderの親クラスであるAbstractItemCountingItemStreamItemReaderにはsetMaxItemCountという読み込み数の最大数が設定できる。このとき、executionContextに現在・最大読み込み数を保存するが、そのキーにsetNameを使用する。このため、名前を設定しないと実行時エラーとなる。

もしこの動作が不要であればsetSaveState(false)でオフにでき、従ってsetNameしなくても例外はスローされなくなる。