Last active
December 21, 2023 13:01
-
-
Save skrb/6fe24dd211f9480c6063c1525b79f13e to your computer and use it in GitHub Desktop.
String Templateのテンプレートを動的に作成する方法
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.Method; | |
import java.io.IOException; | |
import java.util.List; | |
import java.util.Optional; | |
import javax.tools.JavaCompiler; | |
import javax.tools.JavaFileObject; | |
import javax.tools.StandardJavaFileManager; | |
import javax.tools.ToolProvider; | |
public class DynamicTemplateBuilder { | |
public static Optional<StringTemplate> createTemplate(String template, String argName, Object variable) | |
throws IOException, ReflectiveOperationException { | |
// コンパイラの取得 | |
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); | |
if (compiler == null) { | |
return Optional.empty(); | |
} | |
// 仮想ファイルマネージャの取得 | |
try (StandardJavaFileManager fileManager | |
= compiler.getStandardFileManager(null, null, null)) { | |
// コンパイルするファイルの準備 | |
List<? extends JavaFileObject> fileobjs | |
= createJavaFileObjects(template, argName); | |
// コンパイルタスクの生成 | |
JavaCompiler.CompilationTask task | |
= compiler.getTask(null, | |
fileManager, | |
null, | |
List.of("--release", "22", "--enable-preview"), | |
null, | |
fileobjs); | |
// コンパイル | |
if (task.call()) { | |
// クラスのロード | |
ClassLoader loader = ClassLoader.getSystemClassLoader(); | |
Class<?> clss = loader.loadClass("Template"); | |
// Method オブジェクトを取得し、リフレクションで実行する | |
Method method = clss.getMethod("process", String.class); | |
StringTemplate dynamicTemplate | |
= (StringTemplate) method.invoke(null, new Object[]{variable}); | |
return Optional.of(dynamicTemplate); | |
} else { | |
return Optional.empty(); | |
} | |
} | |
} | |
private static List<? extends JavaFileObject> createJavaFileObjects(String template, String argName) { | |
// Java のソースとなる文字列 | |
String templateSrc = STR.""" | |
public class Template { | |
public static StringTemplate process(String \{ argName }) { | |
return java.lang.StringTemplate.RAW.\"\"\" | |
\{ template } | |
\"\"\"; | |
} | |
} | |
""" ; | |
// 文字列をソースとする StringJavaFileObject オブジェクトを | |
// 生成する | |
JavaFileObject fileobj | |
= new StringJavaFileObject("Template", templateSrc); | |
return List.of(fileobj); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\{variable}様 | |
いつもお世話になっております |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.URI; | |
import javax.tools.SimpleJavaFileObject; | |
public class StringJavaFileObject extends SimpleJavaFileObject { | |
private String content; | |
public StringJavaFileObject(String className, String content) { | |
super(URI.create("string:///" | |
+ className.replace('.', '/') | |
+ Kind.SOURCE.extension), | |
Kind.SOURCE); | |
this.content = content; | |
} | |
@Override | |
public CharSequence getCharContent(boolean ignoreEncodingErrors) { | |
return content; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.util.Optional; | |
public class TemplateTest { | |
public static void main(String... args) throws IOException, ReflectiveOperationException { | |
// ファイルからテンプレートを読み込み | |
String template = new String(Files.readAllBytes(Path.of("hello.temp"))); | |
// 動的テンプレート生成 | |
// 第1引数: テンプレート | |
// 第2引数: テンプレートに埋め込む変数名 | |
// 第3引数: テンプレートに埋め込む値 | |
Optional<StringTemplate> dynamicTemplate = DynamicTemplateBuilder.createTemplate(template, "variable", "Bob Dylan"); | |
// 任意のテンプレートプロセッサで処理 | |
dynamicTemplate.ifPresent(t -> { | |
var result = STR.process(t); | |
System.out.println(result); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment