Skip to content

Instantly share code, notes, and snippets.

@skrb
Last active December 21, 2023 13:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skrb/6fe24dd211f9480c6063c1525b79f13e to your computer and use it in GitHub Desktop.
Save skrb/6fe24dd211f9480c6063c1525b79f13e to your computer and use it in GitHub Desktop.
String Templateのテンプレートを動的に作成する方法
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);
}
}
\{variable}様
いつもお世話になっております
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;
}
}
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