SpringBatch的Step块中的泛型方法

时间:2018-10-17 15:09:22

标签: java generics syntax spring-batch

我实际上正在使用Spring Batch,并且我一直在问自己一些有关泛型方法的问题。考虑以下代码:

public <I, O> SimpleStepBuilder<I, O> chunk(int chunkSize) {
    return new SimpleStepBuilder<I, O>(this).chunk(chunkSize);
}

如果我们检查一下源代码,就会发现:

public SimpleStepBuilder<I, O> reader(ItemReader<? extends I> reader) {
    this.reader = reader;
    return this;
}

我不喜欢通过像这样链接电话:

@Bean
public Step step(final AccountReader accountReader, final AccountProcessor accountProcessor) {
    return stepBuilderFactory.get("step")
            .<COR_ACC_ACCOUNT, Account>chunk(10)
            .reader(accountReader)
            .processor(accountProcessor)
            .writer(new JsonWriter<>())
        .build();
}

reader()方法将需要一个ItemProcessor<COR_ACC_ACCOUNT>

我发现这种凉爽可以保持类型安全。

现在是我的问题。给出以下代码:

@Component
public class ItemDictionary {

    private final Map<Class, ItemReader> itemReaders;

    @Autowired
    public ItemDictionary(final List<ItemReader> readers) {
        itemReaders = readers.stream().collect(Collectors.toMap(
                ItemReader::getClass,
                Function.identity()
        ));

    public <I> ItemReader<I> getReader(final Class clazz) {
        return itemReaders.get(clazz);
    }

}

我想像这样定义上面定义的Step

@Bean
public Step step() {
    return stepBuilderFactory.get("step")
            .<COR_ACC_ACCOUNT, Account>chunk(10)
            .reader(<COR_ACC_ACCOUNT>itemDictionary.getReader(AccountReader.class))
            .processor(accountProcessor)
            .writer(new JsonWriter<>())
        .build();
}

itemDictionary基本上是一个Map,其中包含我Spring上下文中存在的所有ItemReader实现。

编译器拒绝此调用<COR_ACC_ACCOUNT>itemDictionary.getReader(AccountReader.class)作为illegal start of expression

我想念什么吗?

是否仍然可以使用ItemDictionnary保留类型安全检查?

2 个答案:

答案 0 :(得分:1)

是的,在Java中该语法实际上是错误的。

您无法在此处保留类型安全性,因为在将实现存储到private final Map<Class, ItemReader> itemReaders

时已经放宽了类型安全性

我建议最简单的解决方案是进行类型转换:

(ItemReader<COR_ACC_ACCOUNT>) itemDictionary.getReader(AccountReader.class)

或者,如果您要解释COR_ACC_ACCOUNT是什么,我们可以做进一步的介绍。我感觉这是一个通用类型,对吗?

    @Bean
    public Step step() {
        return stepBuilderFactory.get("step")
            .<COR_ACC_ACCOUNT, Account>chunk(10)
            .reader((ItemReader<COR_ACC_ACCOUNT>) itemDictionary.getReader(AccountReader.class))
            .processor(accountProcessor)
            .writer(new JsonWriter<>())
            .build();
    }

答案 1 :(得分:0)

根据.<COR_ACC_ACCOUNT, Account>chunk(10),要读取的项目类型为COR_ACC_ACCOUNT,因此AccountReader应该返回该类型的项目,在这种情况下,您无需在此处进行强制转换:< / p>

.reader(<COR_ACC_ACCOUNT>itemDictionary.getReader(AccountReader.class))

我尝试了您的示例,但没有编译错误:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

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.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public ItemDictionary itemDictionary() {
        return new ItemDictionary(Arrays.asList(new FooReader()));
    }

    @Bean
    public ItemWriter<Bar> itemWriter() {
        return null;
    }

    @Bean
    public Step step() {
        return steps.get("step")
                .<Foo, Bar>chunk(5)
                .reader(itemDictionary().getReader(Foo.class))
                .writer(itemWriter())
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(step())
                .build();
    }

    public class ItemDictionary {

        private Map<Class, ItemReader> itemReaders;

        public ItemDictionary(final List<ItemReader> readers) {
            itemReaders = readers.stream().collect(Collectors.toMap(
                    ItemReader::getClass,
                    Function.identity()
            ));
        }

        public <I> ItemReader<I> getReader(final Class clazz) {
            return itemReaders.get(clazz);
        }

    }

    class Foo { }

    class Bar { }

    class FooReader implements ItemReader<Foo> {

        @Override
        public Foo read() {
            return null;
        }
    }

}

希望这会有所帮助。