springプロジェクトにて、jarの中にあるxmlファイルの読み込みを行う設定 FileNotFoundException

springプロジェクトにて、jarの中にあるxmlファイルの読み込みを行う設定 FileNotFoundException

springプロジェクトにて、jarの中にあるxmlファイルの読み込みを行う設定 FileNotFoundException

jar自身がjarの中にあるxmlファイルの読み込みを行う設定 FileNotFoundException

どういうことか・・・
図で解説

hoge.project内のhoge.javaのメソッドから、resourcesディレクトリ内にあるpoge.xmlを読み込ませたいというものです。

IDE上では実際にこういう処理を書きました。
(Xmlには「poge.xml」を入れています。)

public InputStream inputLayoutXml(String Xml) throws IOException {
    
    Resource resource = resourceLoader.getResource("classpath:" + Xml);
    File xmlFile = resource.getFile();
    InputStream fileStream = new FileInputStream(xmlFile);
    
    return fileStream;
}

resources配下を読み込めるようにクラスパスを指定し、poge.xmlを相対指定で設定できるようにしました。
classpathについての分かりやすい説明はこちらで

実際にIDE上では正常に動作させることができました。

上手くいったことを確認しビルドしてjarファイルを作成。jarからの起動を試みました。
するとエラーが発生。

java.io.FileNotFoundException: class path resource [/poge.xml] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/C:/hoge.jar!/poge.xml
        at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:218)
        at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
        at sharedservice.InputFileImpl.inputLayoutXml(InputFileImpl.java:31)
        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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy25.execute(Unknown Source)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
        at org.springframework.batch.core.launch.support.SimpleJobOperator.start(SimpleJobOperator.java:314)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

jarの中にあるxmlを上手く読み込んでくれていない。
ググってみるといくつかヒット。
「リソースがファイルであると仮定するのではなく、入力ストリームを使用して読み取る必要があります。(グーグル翻訳談)」
参考1
参考2

最終的には試していくしかないと思い、system.outでファイル名が読み取れるか試していった。

その1

ResourceLoaderクラスを使ったファイルの読み込み

@Service
public class InputFileImpl implements InputFile {

    @Inject
    ResourceLoader resourceLoader;

    @Override
    public InputStream inputLayoutXml(String Xml) throws IOException {

        System.out.println(Xml);
        System.out.println(resourceLoader.getResource("classpath:" + Xml).getURL().getFile());
        
        File xmlFile = new File(resourceLoader.getResource("classpath:" + Xml).getURL().getFile());
        InputStream fileStream = new FileInputStream(xmlFile);
        return fileStream;
    }
}

結果

poge.xml
file:/C:/hoge.jar!/poge.xml
java.io.FileNotFoundException: file:\C:\hoge.jar!\poge.xml (ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違ってい
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(Unknown Source)
        at java.io.FileInputStream.<init>(Unknown Source)
        at InputFileImpl.inputLayoutXml(InputFileImpl.java:39)
        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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy24.execute(Unknown Source)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
        at org.springframework.batch.core.launch.support.SimpleJobOperator.start(SimpleJobOperator.java:314)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

ファイルのパスは読み込めているがエラーが発生。
よく見ると、「file:\C:\hoge.jar!\poge.xml」って書いてあるのでjarの外側の同じ名前のディレクトリ配下にxmlファイルを呼びに行ってるっぽい。
そりゃjarの中にあるんだから外見てもないわけですよ。

その2

URLクラスに格納して呼び出し

@Service
public class InputFileImpl implements InputFile {

    @Inject
    ResourceLoader resourceLoader;

    @Override
    public InputStream inputLayoutXml(String Xml) throws IOException {

        System.out.println(Xml);
        
        URL url = resourceLoader.getResource("classpath:" + Xml).getURL();
        System.out.println(url);
        
        InputStream fileStream = url.openStream();
        return fileStream;
    }
}

結果

無事jarファイルの中のxmlファイルの読み込みに成功しました。

springカテゴリの最新記事