title: Spring Batch read step running in loop
body: <p>I came across a piece of code that reads some data as the following:</p>
  
  <pre><code>public class StudioReader implements ItemReader&lt;List&lt;Studio&gt;&gt; {
     @Setter private AreaDao areaDao;
     @Getter @Setter private BatchContext context;
     private HopsService hopsService = new HopsService();
  
     @Override
     public List&lt;Studio&gt; read() throws Exception {
        List&lt;Studio&gt; list = hopsService.getStudioHops();
        if (!isEmpty(list)) {
           for (Studio studio : list) {
              log.info("Studio being read: {}", studio.getCode());
              List areaList = areaDao.getArea(studio
                    .getCode());
              if (areaList.size() &gt; 0) {
                 studio.setArea((String) areaList.get(0));
                 log.info("Area {1} is fetched for studio {2}", areaList.get(0), studio.getCode());
              }
              this.getContext().setReadCount(1);
           }
        }
        return list;
     }
  </code></pre>
  
  <p>However when I run the job this read is running in a loop. I found from another stackoverflow <a href="https://stackoverflow.com/questions/28069624/itemreader-reader-in-infinite-loop">answer</a> that it is the expected behavior. My question then is what is the best solution given this particular example? Extend StudioReader from JdbcCursorItemReader ? I found one example that defines everything in the xml which I don't want. And here is the context.xml part for the reader:</p>
  
  <pre><code>  &lt;bean class="org.springframework.batch.core.scope.StepScope" /&gt;
     &lt;bean id="ItemReader" class="com.syc.studio.reader.StudioReader" scope="step"&gt;
        &lt;property name="context" ref="BatchContext" /&gt;
        &lt;property name="areaDao" ref="AreaDao" /&gt;
     &lt;/bean&gt;
  </code></pre>
  
  <p>And here is the job definition in xml:</p>
  
  <pre><code> &lt;bean id="StudioJob" class="org.springframework.batch.core.job.SimpleJob"&gt;
        &lt;property name="steps"&gt;
           &lt;list&gt;
                       &lt;bean id="StudioStep" parent="SimpleStep" &gt;
                       &lt;property name="itemReader" ref="ItemReader"/&gt;
                       &lt;property name="itemWriter" ref="ItemWriter"/&gt;
                       &lt;property name="retryableExceptionClasses"&gt;
                          &lt;map&gt;
                             &lt;entry key="com.syc.studio.exception.CustomException" value="true"/&gt;
                          &lt;/map&gt;
                       &lt;/property&gt;
                       &lt;property name="retryLimit" value="2" /&gt;
                       &lt;/bean&gt;
           &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name="jobRepository" ref="jobRepository" /&gt;
     &lt;/bean&gt;
  </code></pre>
  
  <p>Writer:</p>
  
  <pre><code>public void write(List&lt;? extends Object&gt; obj) throws Exception {
     List&lt;Studio&gt; list = (List&lt;Studio&gt;) obj.get(0);
     for (int i = 0; i &lt;= list.size(); i++) {
        Studio studio = list.get(i);
        if (apiClient == null) {
          apiClient = new APIClient("v2");
       }
        this.uploadXML(studio);
     }
  </code></pre>
  
  <p>The read method after suggestion from @holi-java:</p>
  
  <pre><code>public List&lt;Studio&gt; read() throws Exception {
      if (this.listIterator == null) {
          this.listIterator = initializing();
      }
      return this.listIterator.hasNext() ? this.listIterator.next() : null;
  }
  
  private Iterator&lt;List&lt;Studio&gt;&gt; initializing() {
      List&lt;Studio&gt; listOfStudiosFromApi = hopsService.getStudioLocations();
      for (Studio studio : listOfStudiosFromApi) {
          log.info("Studio being read: {}", studio.getCode());
          List areaList = areaDao.getArea(studio.getCode());
          if (areaList.size() &gt; 0) {
              studio.setArea((String) areaList.get(0));
              log.info("Area {1} is fetched for studio {2}", areaList.get(0), studio.getCode());
          }
          this.getContext().setReadCount(1);
      }
      return Collections.singletonList(listOfStudiosFromApi).iterator();
  }
  </code></pre>