【Java】 Java での リソース の扱いについて

■ はじめに

Javaアプリを作成する際に、
log4j 2の設定ファイル「log4j2.xml」(以下の関連記事を参照)
https://blogs.yahoo.co.jp/dk521123/37495975.html
や Velocity 等のテンプレートファイル XXXXX.vm (以下の関連記事を参照)
https://blogs.yahoo.co.jp/dk521123/34456704.html
を格納する必要がある。
そこで、これらの「リソース」の扱いについて調べてみた。

■ リソースとは?

https://docs.oracle.com/javase/jp/1.5.0/guide/lang/resources.html
より
~~~~~~
プログラムのコードの位置とは無関係な方法で
プログラムがアクセスする必要のあるデータ (イメージ、オーディオ、テキストなど) 
~~~~~~

■ リソース格納場所(デフォルト?)

 * 「src/main/resources」 配下に置く

Java からリソース格納場所を取得する

【1】 ClassLoader.getSystemResource() を使う
【2】 【自クラス】.class.getClass().getResource() を使う
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/ClassLoader.html

構文

URL url = ClassLoader.getSystemResource("【ファイル名 or ディレクトリ名】");

補足1:使用上の注意

[1] 戻り値が URLである
  => 例えば、「file:/C:/【パス】」のような形になる(以下の「サンプル」を参照)

[2] ファイル名 or ディレクトリ名 が存在しない場合は、 null を返却する
  => ClassLoader.getSystemResource(【パス】).toString() ってすると NullPointerで落ちる

[3] 「src/main/resources」 配下に、更にディレクトリを切ってリソースファイルを置く場合     
  => src/main/resources/【フォルダ1】/【フォルダ2】・・・

[4] JARファイルからのリソースパスを取得しようとした場合、実行結果が異なる
  => 以下の「JARファイルでの実行結果」を参照。
    「java.nio.file.FileSystemNotFoundException」が発生している。
  => 以下の関連記事で、JARファイルからのリソースファイルを扱っている
関連記事:JARファイル内のリソースファイルを開いてApache Velocityを使って文字列取得
https://blogs.yahoo.co.jp/dk521123/37515809.html

補足2:AWS Lambdaでのリソースパスの取得

 * AWS Lambdaの場合は、【2】の方法でリソースパスを取得する

補足3:URL => Path への変換

URL => URI => Path で変換可能(もっといい方法があるかもしれないが)
URL url = ClassLoader.getSystemResource("sample.vm");
URI uri = urlForLog4j2xml.toURI();
Path path = Paths.get(uri);

■ サンプル

ディレクトリ構成

C:
 + workspace
    + SampleDemo
       + src
          + main
             + resources
                + log4j2.xml << ファイル
                + mail
                  + templates
                    + sample.vm << ファイル

Demo.java

import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Demo {

  public static void main(String[] args) {
    // 【1】
    System.out.println("【1】");

    // 「src/main/resources」 配下に「log4j2.xml」が存在
    URL urlForLog4j2xml = ClassLoader.getSystemResource("log4j2.xml");
    System.out.println("URL for log4j2.xml : " + urlForLog4j2xml);

    // 存在しないファイル
    URL urlForDummyxml = ClassLoader.getSystemResource("dummy.xml");
    System.out.println("URL for Dummy.xml : " + urlForDummyxml);

    // 「src/main/resources」 配下にディレクトリ「mail/templates」が存在
    URL urlForMailTemplates = ClassLoader.getSystemResource("mail/templates");
    System.out.println("URL for mail/templates : " + urlForMailTemplates);

    // 「src/main/resources」 配下にファイル「mail/templates/sample.vm」が存在
    URL urlForMailTemplatesSampleVm = ClassLoader
        .getSystemResource("mail/templates/sample.vm");
    System.out.println(
        "URL for mail/templates/sample.vm : " + urlForMailTemplatesSampleVm);

    // 【2】
    System.out.println("【2】");

    URL urlForLog4j2xmlPart2 = Demo.class.getClass().getResource("log4j2.xml");
    System.out.println("URL for log4j2.xml : " + urlForLog4j2xmlPart2);

    URL urlForMailTemplatesPart2 = Demo.class.getClass()
        .getResource("mail/templates");
    System.out.println("URL for mail/templates : " + urlForMailTemplatesPart2);

    // 【3】
    System.out.println("【3】");

    InputStream inputStreamForLog4j2xmlPart3 = Demo.class.getClass()
        .getResourceAsStream("log4j2.xml");
    System.out.println("URL for log4j2.xml : " + inputStreamForLog4j2xmlPart3);

    InputStream inputStreamForMailTemplatesPart3 = Demo.class.getClass()
        .getResourceAsStream("mail/templates");
    System.out.println(
        "URL for mail/templates : " + inputStreamForMailTemplatesPart3);

    System.out.println("*****************");

    // i) URL「file:/C:/【パス】」 => Path 「C:/【パス】」に変換
    try {
      URI uriForLog4j2xml = urlForLog4j2xml.toURI();
      System.out.println("i) uriForLog4j2xml = " + uriForLog4j2xml);
      Path pathForLog4j2xml = Paths.get(uriForLog4j2xml);
      System.out.println("i) Path for log4j2.xml : " + pathForLog4j2xml);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    // ii) URL.getPath()
    try {
      System.out.println("ii) Path for log4j2.xml : " + urlForLog4j2xml.getPath());
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    // iii) URI.create(URL「file:/C:/【パス】」) => Path 「C:/【パス】」に変換
    try {
      URI uriForLog4j2xml = URI.create(urlForLog4j2xml.toString());
      System.out.println("iii) uriForLog4j2xml = " + uriForLog4j2xml);
      Path pathForLog4j2xml = Paths.get(uriForLog4j2xml);
      System.out.println("iii) Path for log4j2.xml : " + pathForLog4j2xml);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    
    System.out.println("*****************");
  }
}

出力結果

Eclipse上からの実行結果
【1】
URL for log4j2.xml : file:/C:/work/workspace/SampleDemo/bin/log4j2.xml
URL for Dummy.xml : null
URL for mail/templates : file:/C:/work/workspace/SampleDemo/bin/mail/templates
URL for mail/templates/sample.vm : file:/C:/work/workspace/SampleDemo/bin/mail/templates/sample.vm
【2】
URL for log4j2.xml : null
URL for mail/templates : null
【3】
URL for log4j2.xml : null
URL for mail/templates : null
*****************
i) uriForLog4j2xml = file:/C:/work/workspace/SampleDemo/bin/log4j2.xml
i) Path for log4j2.xml : C:\work\workspace\SampleDemo\bin\log4j2.xml
ii) Path for log4j2.xml : /C:/work/workspace/SampleDemo/bin/log4j2.xml
iii) uriForLog4j2xml = file:/C:/work/workspace/SampleDemo/bin/log4j2.xml
iii) Path for log4j2.xml : C:\work\workspace\SampleDemo\bin\log4j2.xml
*****************
JARファイルでの実行結果
【1】
URL for log4j2.xml : jar:file:/C:/work/workspace/SampleDemo/build/distributions/
HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/log4j2.xml
URL for Dummy.xml : null
URL for mail/templates : jar:file:/C:/work/workspace/SampleDemo/build/distributi
ons/HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/mail/templates
URL for mail/templates/sample.vm : jar:file:/C:/work/workspace/SampleDemo/build/
distributions/HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/mail/templates/sample.v
m
【2】
URL for log4j2.xml : null
URL for mail/templates : null
【3】
URL for log4j2.xml : null
URL for mail/templates : null
*****************
i) uriForLog4j2xml = jar:file:/C:/work/workspace/SampleDemo/build/distributions/
HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/log4j2.xml
java.nio.file.FileSystemNotFoundException
        at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemPr
ovider.java:171)
        at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider
.java:157)
        at java.nio.file.Paths.get(Paths.java:143)
        at com.sample.resources.Demo.main(Demo.java:62)
ii) Path for log4j2.xml : file:/C:/work/workspace/SampleDemo/build/distributions
/HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/log4j2.xml
iii) uriForLog4j2xml = jar:file:/C:/work/workspace/SampleDemo/build/distribution
s/HelloWorld-1.0.0/lib/SampleDemo-1.0.0.jar!/log4j2.xml
java.nio.file.FileSystemNotFoundException
        at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemPr
ovider.java:171)
        at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider
.java:157)
        at java.nio.file.Paths.get(Paths.java:143)
        at com.sample.resources.Demo.main(Demo.java:78)
*****************

関連記事

log4j 2 ~ 入門編 ~

https://blogs.yahoo.co.jp/dk521123/37495975.html

JARファイル内のリソースファイルを開いてApache Velocityを使って文字列取得

https://blogs.yahoo.co.jp/dk521123/37515809.html

Apache Velocity ~入門編~

https://blogs.yahoo.co.jp/dk521123/34456704.html