|
6 | 6 | - [Create a tasklet without a processor](#create-a-tasklet-without-a-processor) |
7 | 7 | - [Java](#java-1) |
8 | 8 | - [Kotlin](#kotlin-1) |
9 | | -- [Use a callback](#use-a-callback) |
| 9 | +- [Create a tasklet without a writer](#create-a-tasklet-without-a-writer) |
10 | 10 | - [Java](#java-2) |
11 | 11 | - [Kotlin](#kotlin-2) |
| 12 | +- [Use a callback](#use-a-callback) |
| 13 | + - [Java](#java-3) |
| 14 | + - [Kotlin](#kotlin-3) |
12 | 15 |
|
13 | 16 | A chunk-oriented step in Spring Batch consists of `ItemReader`, `ItemProcessor`, and `ItemWriter`, which are usually defined separately and then assembled to define a step. However, there are some issues with this approach: it is difficult to share data between `ItemReader`, `ItemProcessor`, and `ItemWriter`, and you need to see each respective file to understand the batch flow. Also, if the classes are not reused, they can make the elements of a job less coherent. |
14 | 17 |
|
@@ -328,9 +331,162 @@ open class TestJobConfig( |
328 | 331 | } |
329 | 332 | ``` |
330 | 333 |
|
| 334 | +## Create a tasklet without a writer |
| 335 | + |
| 336 | +If you need only `ItemStreamReader` and `ItemProcessor` without a writer, you can inherit `ItemStreamIterableReaderProcessor` to define `ItemStreamReader` and `ItemProcessor` in a single class. |
| 337 | + |
| 338 | +### Java |
| 339 | + |
| 340 | +In Java, you can convert a tasklet defined using `AdapterFactory` to `ItemStreamReader` and `ItemProcessor`. |
| 341 | + |
| 342 | +```java |
| 343 | +@Component |
| 344 | +@StepScope |
| 345 | +class SampleTasklet implements ItemStreamIterableReaderProcessor<Integer, String> { |
| 346 | + |
| 347 | + @Value("#{jobParameters['totalCount']}") |
| 348 | + private long totalCount; |
| 349 | + |
| 350 | + private int count = 0; |
| 351 | + |
| 352 | + @NonNull |
| 353 | + @Override |
| 354 | + public Iterable<? extends Integer> readIterable(@NonNull ExecutionContext executionContext) { |
| 355 | + System.out.println("totalCount: " + totalCount); |
| 356 | + return () -> new Iterator<>() { |
| 357 | + @Override |
| 358 | + public boolean hasNext() { |
| 359 | + return count < totalCount; |
| 360 | + } |
| 361 | + |
| 362 | + @Override |
| 363 | + public Integer next() { |
| 364 | + return count++; |
| 365 | + } |
| 366 | + }; |
| 367 | + } |
| 368 | + |
| 369 | + @Override |
| 370 | + public String process(@NonNull Integer item) { |
| 371 | + return "'" + item.toString() + "'"; |
| 372 | + } |
| 373 | +} |
| 374 | +``` |
| 375 | + |
| 376 | +```java |
| 377 | +@Configuration |
| 378 | +public class TestJobConfig { |
| 379 | + |
| 380 | + @Bean |
| 381 | + public Job testJob( |
| 382 | + SampleTasklet sampleTasklet, |
| 383 | + JobRepository jobRepository, |
| 384 | + PlatformTransactionManager transactionManager |
| 385 | + ) { |
| 386 | + return new JobBuilder("testJob", jobRepository) |
| 387 | + .start( |
| 388 | + new StepBuilder("testStep", jobRepository) |
| 389 | + .<Integer, String>chunk(3, transactionManager) |
| 390 | + .reader(AdapterFactory.itemStreamReader(sampleTasklet)) |
| 391 | + .processor(AdapterFactory.itemProcessor(sampleTasklet)) |
| 392 | + .writer(chunk -> System.out.println(chunk.getItems())) |
| 393 | + .build() |
| 394 | + ) |
| 395 | + .build(); |
| 396 | + } |
| 397 | +} |
| 398 | +``` |
| 399 | + |
| 400 | +You can statically import the method of `AdapterFactory` for better readability. |
| 401 | + |
| 402 | +```java |
| 403 | +import static com.navercorp.spring.batch.plus.step.AdapterFactory.itemStreamReader; |
| 404 | +import static com.navercorp.spring.batch.plus.step.AdapterFactory.itemStreamWriter; |
| 405 | + |
| 406 | +... |
| 407 | + |
| 408 | +@Configuration |
| 409 | +public class TestJobConfig { |
| 410 | + |
| 411 | + @Bean |
| 412 | + public Job testJob( |
| 413 | + SampleTasklet sampleTasklet, |
| 414 | + JobRepository jobRepository, |
| 415 | + PlatformTransactionManager transactionManager |
| 416 | + ) { |
| 417 | + return new JobBuilder("testJob", jobRepository) |
| 418 | + .start( |
| 419 | + new StepBuilder("testStep", jobRepository) |
| 420 | + .<Integer, String>chunk(3, transactionManager) |
| 421 | + .reader(itemStreamReader(sampleTasklet)) |
| 422 | + .processor(itemProcessor(sampleTasklet)) |
| 423 | + .writer(chunk -> System.out.println(chunk.getItems())) |
| 424 | + .build() |
| 425 | + ) |
| 426 | + .build(); |
| 427 | + } |
| 428 | +} |
| 429 | +``` |
| 430 | + |
| 431 | +### Kotlin |
| 432 | + |
| 433 | +In Kotlin, you can easily convert a tasklet defined using an extension function in Spring Batch Plus to `ItemStreamReader` and `ItemProcessor`. |
| 434 | + |
| 435 | +```Kotlin |
| 436 | +@Component |
| 437 | +@StepScope |
| 438 | +open class SampleTasklet( |
| 439 | + @Value("#{jobParameters['totalCount']}") private var totalCount: Long, |
| 440 | +) : ItemStreamIterableReaderProcessor<Int, String> { |
| 441 | + private var count = 0 |
| 442 | + |
| 443 | + override fun readIterable(executionContext: ExecutionContext): Iterable<Int> { |
| 444 | + println("totalCount: $totalCount") |
| 445 | + return Iterable { |
| 446 | + object : Iterator<Int> { |
| 447 | + override fun hasNext(): Boolean { |
| 448 | + return count < totalCount |
| 449 | + } |
| 450 | + |
| 451 | + override fun next(): Int { |
| 452 | + return count++ |
| 453 | + } |
| 454 | + } |
| 455 | + } |
| 456 | + } |
| 457 | + |
| 458 | + override fun process(item: Int): String? { |
| 459 | + return "'$item'" |
| 460 | + } |
| 461 | +} |
| 462 | +``` |
| 463 | + |
| 464 | +```Kotlin |
| 465 | +@Configuration |
| 466 | +open class TestJobConfig( |
| 467 | + private val batch: BatchDsl, |
| 468 | + private val transactionManager: PlatformTransactionManager, |
| 469 | +) { |
| 470 | + @Bean |
| 471 | + open fun testJob( |
| 472 | + sampleTasklet: SampleTasklet, |
| 473 | + ): Job = batch { |
| 474 | + job("testJob") { |
| 475 | + step("testStep") { |
| 476 | + chunk<Int, String>(3, transactionManager) { |
| 477 | + reader(sampleTasklet.asItemStreamReader()) |
| 478 | + processor(sampleTasklet.asItemProcessor()) |
| 479 | + writer { chunk -> println(chunk.items) } |
| 480 | + } |
| 481 | + } |
| 482 | + } |
| 483 | + } |
| 484 | +} |
| 485 | +``` |
| 486 | + |
331 | 487 | ## Use a callback |
332 | 488 |
|
333 | | -You can define a callback method for `ItemStream` of `ItemStreamWriter` in `ItemStreamIterableReaderProcessorWriter` and `ItemStreamIterableReaderWriter`. You can selectively define a callback method. |
| 489 | +You can define a callback method for `ItemStream`. You can selectively define a callback method. |
334 | 490 |
|
335 | 491 | ### Java |
336 | 492 |
|
|
0 commit comments