Spring Batch 2.0: Current Resource of a MultiResourceItemReader

[UPDATE. This feature is available on Spring Batch 2.0.1. Thanks for your interest, Dan. So, following code it’s just only an exercise on reflection and dirty access to private methods and fields]

MultiResourceItemReader class reads items from multiple resources sequentially.

Below a classic job configuration using this feature is exposed.




    
        
            
                
            
        
    

    

    


  

  
     <!-- Configuration omitted -->
  

  
     <!-- Configuration omitted -->
  


Note. “job”, “step”, “tasklet” and “chunk” must appear as “batch:job”,… in the listing above, but WordPress sourcecode plugin does not want to show them so.

In some scenarios should be useful to know resource file name at processing time in order to perform some mappings or writings depending on this file name. However, there is no path to access this information using Spring Batch API.

So, MultiResourceItemReader must be modified (in a some dirty way) to share resource name across the Step Context.

import java.lang.reflect.Field;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.core.io.Resource;

public class CustomMultiResourceItemReader extends MultiResourceItemReader
	<list > {

  private static final Logger log = Logger.getLogger(CustomMultiResourceItemReader.class.getName());

  @Override
  public void open(ExecutionContext executionContext) throws ItemStreamException {

    super.open(executionContext);

    try {

      Field resourcesField = MultiResourceItemReader.class.getDeclaredField("resources");
      resourcesField.setAccessible(true);
      Resource[] resources = (Resource[]) resourcesField.get(this);

      executionContext.put("current.resource.name", resources[0].getFilename());

    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }

  @Override
  public void update(ExecutionContext executionContext) throws ItemStreamException {

    super.update(executionContext);

    try {

      Field indexField = MultiResourceItemReader.class.getDeclaredField("index");
      indexField.setAccessible(true);
      Object index = indexField.get(this);

      Field currentResourceField = index.getClass().getDeclaredField("currentResource");
      currentResourceField.setAccessible(true);
      Integer currentResource = (Integer)currentResourceField.get(index);

      Field resourcesField = MultiResourceItemReader.class.getDeclaredField("resources");
      resourcesField.setAccessible(true);
      Resource[] resources = (Resource[]) resourcesField.get(this);

      if (currentResource < resources.length) {
          executionContext.put("current.resource.name", resources[currentResource].getFile().getPath());
      } else {
          executionContext.put("current.resource.name", null);
      }

    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }

}

Note that this modification may only work with Spring Batch 2.0 because it's accessing private fields and methods within core classes.

2 comentarios en “Spring Batch 2.0: Current Resource of a MultiResourceItemReader

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s