Daily Archives: April 15, 2016

Read file name when using MultiResourceItemReader in Springbatch

Springbatch provides MultiResourceItemReader to allow us to read all files in a folder:

<bean id="filenameReader" class=" org.springframework.batch.item.file.MultiResourceItemReader">
    <property name="resources" value="file:SpringBatchReadFilename/tmp/*.csv" />
    <property name="delegate" ref="filenameFlatReader" />
</bean>

However, there maybe some cases that we want. Assume we have below 2 files and we want to output the filename in processor or writer.

20160402.csv
id,value
4,d

20160403.csv
id,value
1,a
2,b
3,c

How do we do that? My friend Yidong Du provides an brilliant solution: write a self-defined FlatFileItemReader and overwrite setResource(), doReader() methods. In each doReader set the filename in entity:

@Data
public class FilenameItemReader extends FlatFileItemReader<FilenameEntity> {

    private Resource myresource;

    @Override
    public void setResource(Resource var1) {
        super.setResource(var1);
        myresource = var1;
    }

    @Override
    protected FilenameEntity doRead() throws Exception {
        FilenameEntity filenameEntity = super.doRead();
        if (filenameEntity == null) {
            return null;
        }
        filenameEntity.setFileName(myresource.getFile().getName());
        return filenameEntity;
    }

}

In writer, it writes the entities with fileName:
FilenameEntity(id=4, value=d, fileName=20160402.csv)
FilenameEntity(id=1, value=a, fileName=20160403.csv)
FilenameEntity(id=2, value=b, fileName=20160403.csv)
FilenameEntity(id=3, value=c, fileName=20160403.csv)

Check my code on github: link

log4j output to different log files

Normally when we load a logger in Java, we do like below:

private static Logger logger = LoggerFactory.getLogger(App.class);

Or

private Logger logger3 = LoggerFactory.getLogger(getClass());

Logger like this will by default load the root logger.

Alternatively, we can define our own logger. And we can add appender to self-defined logger. In this way, we can output to different log files by using different logger.

Below is an example.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true">

       <appender name="console" class="org.apache.log4j.ConsoleAppender">
              <layout class="org.apache.log4j.PatternLayout">
                     <param name="ConversionPattern"
                            value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
              </layout>
       </appender>

       <appender name="file" class="org.apache.log4j.RollingFileAppender">
              <param name="append" value="true" />
              <param name="maxFileSize" value="1MB" />
              <param name="maxBackupIndex" value="10" />
              <param name="file" value="test.log" />
              <layout class="org.apache.log4j.PatternLayout">
                     <param name="ConversionPattern"
                            value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
              </layout>
       </appender>

       <appender name="myFile" class="org.apache.log4j.RollingFileAppender">
              <param name="append" value="true" />
              <param name="maxFileSize" value="1MB" />
              <param name="maxBackupIndex" value="10" />
              <param name="file" value="test2.log" />
              <layout class="org.apache.log4j.PatternLayout">
                     <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
              </layout>
       </appender>

       <!--A self defined logger. It is used to output into a separate file. By default, additivity is true.
       If additivity=true, sub logger will append to root logger.
       If additivity=false, sub logger won't append to root logger.
       -->
       <logger name="logger2" additivity="true">
              <level value="INFO" />
              <appender-ref ref="myFile" />
       </logger>

       <root>
              <level value="DEBUG" />
              <appender-ref ref="console" />
              <appender-ref ref="file" />
       </root>

</log4j:configuration>

App.java

public class App {

    private static Logger logger = LoggerFactory.getLogger(App.class);
    private static Logger logger2 = LoggerFactory.getLogger("logger2");

    public static void main(String[] args) {
        logger.info("information");
        logger.warn("warning");
        logger.error("error");
        logger2.info("self-defined logger");
    }
}

Root logger output to test.log with “information”, “warning” and “error”, logger2 output to test2.log with “self-defined logger.
Another thing we should notice is additivity=”true” parameter in logger. If it is set true, all the sub logger will also be output by root logger. If it is set as false, it won’t show in root logger.
Check my code on github: link