Announcement Announcement Module
Collapse
No announcement yet.
Getting objects from JobExecutionContext Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Getting objects from JobExecutionContext

    Hi!

    I'm working on a batch and have a problem;

    I want an object to be passed along from start to finish ... being initialized (and "terminated/handled") in the JobStatusListener. I want the itemReader and itemWriter to be able to get this object, write to it, and pass it along again.

    Just using this;
    <property name="someObject" value="#{jobExecutionContext[someKey]}" />
    does NOT work, as it's not able to set the modified object back to the executionContext.

    I've tried whats in the chapter 11.8. Passing Data to Future Steps in the documentation, but this didn't work (and does not make much sense to me), as the @BeforeStep method in the reader and writer was never touched... and I've seen some text explaining that they have to be listeners to make this work.., but they are reader and writer... .... so how do I get the JobExecutionContext within the reader and writer?

    ("implements JobExecutionContextAware" would be a nice feature...)

  • #2
    First, when using late-binding (the "#{}" syntax), make sure that your bean has scope="step".

    Second, when you put a @BeforeStep annotation, make sure that the class is registered as a listener by referencing it from a <listener/> tag.

    If you have these things correct, then post your configuration and we can check it out. (Be sure to use the CODE tags when posting the code).

    Comment


    • #3
      Originally posted by DHGarrette View Post
      First, when using late-binding (the "#{}" syntax), make sure that your bean has scope="step".

      Second, when you put a @BeforeStep annotation, make sure that the class is registered as a listener by referencing it from a <listener/> tag.
      #1: done.
      #2: Does this mean that my ItemReader and ItemWriter has to implement StepListener? (if so; should it be referred to as itemReader AND listener..., or just listener?)

      In the documentation it looks like this (no StepListener here...);
      Code:
      public void SavingItemWriter implements ItemWriter<Object> {
          private StepExecution stepExecution;
      
          public void write(List<? extends Object> items) throws Exception {
              // ...
      
              ExecutionContext stepContext = this.stepExecution.getExecutionContext();
              stepContext.put("someKey", someObject);
          }
      
          @BeforeStep
          public void saveStepExecution(StepExecution stepExecution) {
              this.stepExecution = stepExecution;
          }

      Comment


      • #4
        If you use the listener annotation, you do *not* need to implement a listener interface (that's one of the benefits). All you have to do is wire it into the step with the <listener/> tag. We take care of the rest.

        Comment


        • #5
          Originally posted by DHGarrette View Post
          If you use the listener annotation, you do *not* need to implement a listener interface (that's one of the benefits). All you have to do is wire it into the step with the <listener/> tag. We take care of the rest.
          Ok... that's nice! The step configuration looks like this;
          Code:
          <bean id="bu28Step" class="org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean">
              <property name="transactionManager" ref="transactionManager" />
              <property name="jobRepository" ref="mapJobRepository" />
              <property name="itemReader" ref="bu28sItemReader" />
              <property name="itemWriter" ref="bu28sWriter" />
              <property name="commitInterval" value="1" />
              <property name="skippableExceptionClasses">
                  <list>
                      <value>com.myTest.batch.common.exception.UncheckedException</value>
                  </list>
              </property>
              <property name="skipLimit" value="100000"/>
          </bean>
          So how do I add the property?
          This didn't work;
          Code:
              <property name="listeners">
                  <list>
                      <ref bean="bu28sItemReader" />
                      <ref bean="bu28sWriter" />
                  </list>
              </property>
          This DID work.... but I found it rather .... cumbersome (also found here; http://jira.springframework.org/browse/BATCH-1135);
          Code:
          <property name="listeners">
                      <list>
                          <batch:step-listener ref="bu28sItemReader"/>
                          <batch:step-listener ref="bu28sWriter"/>
                      </list>
                  </property>
          ... however; this method in the reader AND writer was never executed:
          Code:
          @BeforeStep
              public void saveStepExecution(StepExecution stepExecution) 
              {
                  System.out.println("\nSetting StepExecution!!\n");
                  this.stepExecution = stepExecution;
              }
          ... and stepExecution remained null.

          (using spring-batch-core 2.0.1.RELEASE)
          Last edited by knutivar; Sep 18th, 2009, 03:05 AM.

          Comment


          • #6
            Any stack trace, or error message?

            Comment


            • #7
              Originally posted by Dave Syer View Post
              Any stack trace, or error message?
              No.
              When I use the configuration that deploys, I only get a nullpointerException when trying to access the stepExecution.
              I should be able to see output from this;
              Code:
              @BeforeStep
                  public void saveStepExecution(StepExecution stepExecution)
                  {
                      System.out.println("\nSetting StepExecution!!\n");
                      this.stepExecution = stepExecution;
                  }
              ... but none appears.

              The stepConfiguration with "everything";
              Code:
              <bean id="bu28Step" class="org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean">
                  <property name="transactionManager" ref="transactionManager"/>
                  <property name="jobRepository" ref="mapJobRepository"/>
                  <property name="itemReader" ref="bu28sItemReader"/>
                  <property name="itemWriter" ref="bu28sWriter"/>
                  <property name="listeners">
                      <list>
                          <batch:step-listener ref="bu28sItemReader"/>
                          <batch:step-listener ref="bu28sWriter"/>
                      </list>
                  </property>
                  <property name="commitInterval" value="1" />
                  <property name="skippableExceptionClasses">
                      <list>
                          <value>com.myTest.batch.common.exception.UncheckedException</value>
                      </list>
                  </property>
                  <property name="skipLimit" value="100000"/>
              </bean>

              Comment


              • #8
                The resolving of the listener annotation is done by the batch namespace handler. If you don't use the <listener/> (or equivalently, <step-listener/>) tag, then nothing will ever handle the annotation.

                Is there a reason you are not using the batch namespace to configure your step? Its purpose is to make your job easier.

                If you really don't want to use the namespace at all (even for the <listener/> tag), then you can remove the annotation and just make your listener class implement the StepExecutionListener interface. That's the 1.x way of doing it, and it will still work.

                Comment


                • #9
                  Originally posted by DHGarrette View Post
                  Is there a reason you are not using the batch namespace to configure your step?
                  ... no, sadly. Ignorance?

                  Well; I tried to configure it like in the samples supplied by SpringBatch..., and ended up with this;

                  Code:
                  <batch:job id="bu28s" job-repository="mapJobRepository">
                      <batch:step id="bu28Step">
                          <batch:tasklet>
                              <batch:chunk reader="bu28sItemReader" writer="bu28sWriter" commit-interval="1" skip-limit="100000">
                                  <batch:streams>
                                      <batch:stream ref="bu28sItemReader" />
                                  </batch:streams>
                                  <batch:skippable-exception-classes>
                                      com.infosynergi.framework.yafr.common.exception.UncheckedException
                                  </batch:skippable-exception-classes>
                             </batch:chunk>
                              <batch:listeners>
                                  <batch:listener ref="bu28sItemReader" />
                                  <batch:listener ref="bu28sWriter" />
                              </batch:listeners>
                          </batch:tasklet>
                      </batch:step>
                      <batch:listeners>
                          <batch:listener ref="jobExecutionListener" />
                      </batch:listeners>
                  </batch:job>
                  However; this gave me an error; NoSuchJobException: No job configuration with the name [bu28s] was registered.

                  My old job-definition had a "name" tag. May it be that the new configuration lacks this?

                  The old job configuration;
                  Code:
                  <bean id="bu28s" class="org.springframework.batch.core.job.SimpleJob">
                      <property name="name" value="bu28s"/>
                      <property name="steps">
                          <list>
                              <ref local="bu28Step"/>
                          </list>
                      </property>
                      <property name="jobRepository" ref="mapJobRepository"/>
                      <property name="jobExecutionListeners">
                          <list>
                              <ref bean="jobExecutionListener"/>
                          </list>
                      </property>
                  </bean>
                  When I used the old job-configuration, I got a problem saying that there were not any bean named jobRepository defined..., how can i set the step to look for mapJobRepository instead?

                  ... and one more thing; my "original" step had a transactionManager defined. In the "new" configuration, I have not seen any place to refer to it... Is it somehow automagically found?

                  Comment


                  • #10
                    Originally posted by knutivar View Post
                    However; this gave me an error; NoSuchJobException: No job configuration with the name [bu28s] was registered.
                    I'm not sure what would cause that. Maybe try comparing with the samples and see what the differences are?

                    Originally posted by knutivar View Post
                    My old job-definition had a "name" tag. May it be that the new configuration lacks this?
                    The "id" attribute is used for the bean's "name".

                    Originally posted by knutivar View Post
                    When I used the old job-configuration, I got a problem saying that there were not any bean named jobRepository defined..., how can i set the step to look for mapJobRepository instead?
                    The "job-repository" attribute is used for this. It defaults to "jobRepository", but using the attribute overrides that.

                    Originally posted by knutivar View Post
                    ... and one more thing; my "original" step had a transactionManager defined. In the "new" configuration, I have not seen any place to refer to it... Is it somehow automagically found?
                    The optional transaction-manager" attribute defaults to "transactionManager", so if your bean is named "transactionManager", then you're fine.

                    Comment

                    Working...
                    X