# 4. The writer, the beanMapped trap, and finding the partition's own name [← Previous](03-what-gridsize-actually-controls.md) | [README](../README.md) | [Next: The diagnostic endpoint →](05-the-diagnostic-endpoint.md) ## Not beanMapped(), again [The earlier `spring-batch` module](https://ankurm.com/) already found this once: `Order` and `RiskScoredOrder` are Java records, and `JdbcBatchItemWriterBuilder.beanMapped()` binds SQL parameters through `BeanPropertySqlParameterSource`, which looks for JavaBean-style getters (`getOrderId()`). A record's accessors are `orderId()`, no `get` prefix — `beanMapped()` would silently bind every column to `NULL` against this exact shape, because `BeanPropertySqlParameterSource` treats a missing getter as an absent property rather than an error. This module's [`riskWriter`](../src/main/java/com/ankurm/batchpartition/config/BatchConfig.java) uses an explicit `itemPreparedStatementSetter` instead, precisely to avoid rediscovering that bug a second time. ## Finding out which partition wrote which row `ORDER_RISK_SUMMARY.partition_name` exists so a reader (or a bug report) can tell which worker wrote a given row. The first attempt to populate it reached for `StepSynchronizationManager.getContext().getStepExecution().getStepName()` inside the `itemPreparedStatementSetter` lambda, guessing the class lived at `org.springframework.batch.core.step.StepSynchronizationManager` by analogy with `StepExecution` living in `org.springframework.batch.core.step`. It does not compile: ``` error: package org.springframework.batch.core.step does not exist (well -- StepSynchronizationManager specifically does not exist there) ``` `javap` against the real jar answers where it actually is: [`docs/output/03-package-repackaging-javap.txt`](output/03-package-repackaging-javap.txt) shows `org.springframework.batch.core.scope.context.StepSynchronizationManager` — alongside `JobScope` and `StepScope`'s own scope-context machinery, which is the more sensible package for it in hindsight; the guess just followed the wrong analogy. The fix that shipped is simpler than getting the import right would have been: late-bind the step name directly, the same mechanism [chapter 2](02-anatomy-of-a-partitioned-step.md) already uses for the shard file path. ```java @Bean @StepScope public ItemWriter riskWriter(JdbcTemplate jdbcTemplate, @Value("#{stepExecution.stepName}") String partitionName) { return new JdbcBatchItemWriterBuilder() .dataSource(jdbcTemplate.getDataSource()) .sql("MERGE INTO ORDER_RISK_SUMMARY (order_id, customer_id, amount_cents, region, " + "risk_score, high_risk, partition_name) KEY(order_id) VALUES (?, ?, ?, ?, ?, ?, ?)") .itemPreparedStatementSetter((item, ps) -> { // ... ps.setString(7, partitionName); }) .assertUpdates(true) .build(); } ``` `#{stepExecution.stepName}` reaches the *current* `StepExecution`'s name (`ordersWorkerStep:partition2`, for instance) through the same `@StepScope` proxy machinery that resolves `#{stepExecutionContext['fileName']}` — no lookup class needed, no package to get wrong. `MERGE ... KEY(order_id)` (H2 upsert syntax) rather than a plain `INSERT` was a deliberate second choice: it makes re-running a single partition idempotent, which matters once [chapter 8](08-restart-reruns-only-the-failed-partition.md) starts re-executing partitions after a failure. ## Going deeper - `BeanPropertySqlParameterSource` and why it fails silently rather than throwing: [Spring Framework Javadoc](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/BeanPropertySqlParameterSource.html) (`rel="nofollow"`). - The full list of classes this article's research found relocated in Spring Batch 6.0: [`docs/output/03-package-repackaging-javap.txt`](output/03-package-repackaging-javap.txt). [Next: The diagnostic endpoint →](05-the-diagnostic-endpoint.md)