Results 1 to 8 of 8

Thread: Getting Current Resource Filename in ItemReader

  1. #1

    Question Getting Current Resource Filename in ItemReader

    Hi,

    I currently have a class InvoiceFileItemReader which implements ItemReader. I am overriding the read() method and I need to access the filename of the currently executing file. I know that a MultiResourceItemReader has a getCurrentResource() method. I want to do the same sort of thing using an ItemReader.

    What is the best possible way to achieve this?

    Any help will be greatly appreciated.

    Thanks,

  2. #2
    Join Date
    Sep 2008
    Location
    Chicagoland, IL
    Posts
    349

    Default

    Where is the source of the filename? Where are you looking to retrieve it from?
    Michael Minella
    Spring Batch Lead
    Author - Pro Spring Batch
    http://www.michaelminella.com
    Twitter: @MichaelMinella

  3. #3

    Default

    Hi mminella,

    Thanks for your response. Let me provide you with more information as well as my configuration. I am fairly new to Spring and Spring Batch so I am not sure if what I have done is correct.

    An extract of invoice-context.xml
    Code:
    <bean id="invoiceFileReader" class="za.org.joburg.shared.batch.InvoiceFileItemReader">
    	<property name="delegate" ref="ffItemReader" />
    	<property name="exceptionDAO" ref="exceptionDAO"/>
    </bean>
    
    <bean id="ffItemReader" class="org.springframework.batch.item.file.MultiResourceItemReader">
    	<property name="strict" value="false" />
    	<property name="resources" value="${batch.inv.file.location}" />
    	<property name="delegate">
    		<bean class="org.springframework.batch.item.file.FlatFileItemReader">
    			<property name="strict" value="false" />
    			<property name="lineMapper">
    				<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
    					<property name="lineTokenizer" ref="invoiceFileTokenizer" />
    					<property name="fieldSetMapper">
    						<bean class="org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper" />
    					</property>
    				</bean>
    			</property>
    		</bean>
    	</property>
    </bean>
    As you can see from the configuration above, the list of files is in a directory and I read the location from a properties file.

    An extract from InvoiceFileItemReader.java
    Code:
    public class InvoiceFileItemReader implements ItemReader<SourceFile> {
    	private ItemReader<FieldSet> delegate;
    
    	public ItemReader<FieldSet> getDelegate() {
    		return delegate;
    	}
    
    	public void setDelegate(ItemReader<FieldSet> delegate) {
    		this.delegate = delegate;
    	}
    
    	public SourceFile read() throws Exception, UnexpectedInputException, ParseException {
    		SourceFile sourceFile = new SourceFile();
    		sourceFile.setFilename(((MultiResourceItemReader<FieldSet>) delegate).getCurrentResource().getFilename());
    	}
    {
    When I try and cast the delegate (ItemReader) to a MultiResourceItemReader I get the following exception:
    Code:
    java.lang.ClassCastException: $Proxy30 cannot be cast to org.springframework.batch.item.file.MultiResourceItemReader
    	at za.org.joburg.shared.batch.InvoiceFileItemReader.read(InvoiceFileItemReader.java:61)
    	at za.org.joburg.shared.batch.InvoiceFileItemReader.read(InvoiceFileItemReader.java:1)
    	at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:90)
    	at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:127)
    	at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:106)
    	at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    	at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    	at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    	at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:103)
    	at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:68)
    	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:353)
    	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
    	at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:261)
    	at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
    	at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    	at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    	at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    	at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:247)
    	at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:196)
    	at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
    	at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
    	at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    	at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
    	at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
    	at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    	at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
    	at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
    	at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48)
    	at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114)
    	at za.org.joburg.shared.web.controller.JobLauncherController.launch(JobLauncherController.java:34)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    	at java.lang.reflect.Method.invoke(Unknown Source)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
    	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    	at java.lang.Thread.run(Unknown Source)
    I understand what the problem is but I don't know how to fix it. Please advise on what I need to do or change to get the filename.

    Thanks so much,

  4. #4
    Join Date
    Sep 2008
    Location
    Chicagoland, IL
    Posts
    349

    Default

    Two things:
    1. Why is the delegate a proxy in this case? Are you doing any type of AOP that isn't in the configuration provided?
    2. If you are willing to use the current snapshot for Spring Batch, we actually have a new feature than handles what you are attempting to do for you. We have created a new interface called ResourceAware. If your item implements this interface, when being read in from a MultiResourceItemReader, we will inject the resource the item came from automatically (no additional code required from you). We'd love any feedback on the new feature!
    Michael Minella
    Spring Batch Lead
    Author - Pro Spring Batch
    http://www.michaelminella.com
    Twitter: @MichaelMinella

  5. #5

    Default

    Hi Martin,

    Sorry I am still new to the whole proxy aspect of things. As far as I know the configuration provided is the only configuration that is being used.

    Originally the InvoiceFileItemReader had it's delegate declared as a MultiResourceItemReader but that also led me to a ClassCastException because apparently I had to code to the interface ItemReader rather than the concrete class MultiResourceItemReader . My original post can be found here: http://forum.springsource.org/showth...695#post434695

    In terms of ResourceAware would I then implement both ItemReader and ResourceAware?

    Thanks so much again for your quick response.

  6. #6
    Join Date
    Sep 2008
    Location
    Chicagoland, IL
    Posts
    349

    Default

    Using the new feature I described, you wouldn't need your InvoiceFileItemReader at all. Your SourceFile class would implement ResourceAware and you would just use the MultiResourceItemReader. We take care of the rest. You can see the new interface (ResourceAware) here: https://github.com/SpringSource/spri...urceAware.java
    Michael Minella
    Spring Batch Lead
    Author - Pro Spring Batch
    http://www.michaelminella.com
    Twitter: @MichaelMinella

  7. #7

    Default

    Thanks, I will have to investigate and see how it works. The reason why I wrote a class that implements ItemReader is because I needed to process lines according to a specific token in the line.

  8. #8
    Join Date
    Sep 2008
    Location
    Chicagoland, IL
    Posts
    349

    Default

    The FlatFileItemReader supports custom tokens including dynamic ones. Take a look at the DelimitedLineTokenzier. While a comma is the default delimiter, you can configure any character you want (you can use a String in the current snapshot version). You can also implement your own LineTokenizer to parse the given line however you need. I would shy away from creating an entire ItemReader just to parse a line though.
    Michael Minella
    Spring Batch Lead
    Author - Pro Spring Batch
    http://www.michaelminella.com
    Twitter: @MichaelMinella

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •