Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Batch FlatFileItemWriter - How to use stepExecution.jobId to generate file name

Tags:

spring-batch

I have this FileWriter where I'm trying to append the current Job Id to the filename that is generated.

<bean id="csvFileWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
    <property name="resource">
        <bean class="org.springframework.core.io.FileSystemResource">
            <constructor-arg type="java.lang.String">
                <value>${csv.file}_#{stepExecution.jobExecution.jobId}</value>
            </constructor-arg>
        </bean>
    </property>
    <property name="lineAggregator">
        <bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
            <property name="delimiter">
                <util:constant
                    static-field="org.springframework.batch.item.file.transform.DelimitedLineTokenizer.DELIMITER_COMMA"/>
            </property>
            <property name="fieldExtractor">
                <bean class="org.springframework.batch.item.file.transform.PassThroughFieldExtractor" />
            </property>
        </bean>
    </property>
    ....
....

but it's bombing out with

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'stepExecution' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:208)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:72)
    at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:52)
    at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102)
    at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:97)
    at org.springframework.expression.common.CompositeStringExpression.getValue(CompositeStringExpression.java:82)
    at org.springframework.expression.common.CompositeStringExpression.getValue(CompositeStringExpression.java:1)
    at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:139)
    ... 45 more

Any idea how i can correctly reference the jobId in this case?

Update: Adding worked solution

I implemented the JobExecutionListener which adds the jobId to the ExecutionContext

public class MyExecutionListener implements JobExecutionListener {

    public void beforeJob(JobExecution jobExecution) {
        long jobId = jobExecution.getJobId();
        jobExecution.getExecutionContext().put("jobId",jobId);
        jobExecution.getExecutionContext().put("date",date);
    }

    public void afterJob(JobExecution jobExecution) {

Register the listener to the batch job

<batch:job id="batchJob">
    <batch:listeners>
        <batch:listener ref="myExecutionListener"/>
    </batch:listeners>

And finally the CSV writer gets updated to

<bean id="fundAssetCsvFileWriter"
    class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
    <property name="resource">
        <bean class="org.springframework.core.io.FileSystemResource">
            <constructor-arg value="${csv.file.name}_#{jobExecutionContext['date']}_#{jobExecutionContext['jobId']}.csv" type="java.lang.String"/>
        </bean>
like image 767
emeraldjava Avatar asked Feb 04 '14 10:02

emeraldjava


1 Answers

The supported names for late-bindig are:

  • #{jobParameters}
  • #{jobExecutionContext}
  • #{stepExecutionContext}

If jobId is not directly accessible, look this question.

Also, resource can be injected directly as

<property name="resource">
  <value>file://${csv.file}_#{jobExecutionContext['jobId']}</value>
</property>

because the right resource type is created using a converter.

like image 68
Luca Basso Ricci Avatar answered Sep 20 '22 17:09

Luca Basso Ricci