
タイプセーフなJava Mustacheテンプレートエンジン。
テンプレートは読みやすいJavaソースコードにコンパイルされ、値のバインディングは静的にチェックされます。
ドキュメントはjavadoc.ioにもありますが、上記のように集約されていません。集約されたjavadocが推奨されるドキュメントであり、このreadmeの残りは主にプロパガンダマーケティング目的です。
以前のリリースの場合:
https://jstach.io/doc/jstachio/VERSION/apidocs
ここでVERSIONは希望するバージョンです。
why_jstachio_is_better.mdで説明されています。
ロジックレスのMustache (v 1.3)構文。
今日からJEP 430のようなサポートを、さらに強力に利用できます。
テンプレートはJavaコードにコンパイルされます
値のバインディングは静的にチェックされます。
メソッド、フィールド、getterメソッドをテンプレート内で参照できます。
コンテキスト付きの親切なエラーメッセージ。
設定不要。プラグインや調整は不要です。すべて標準のjavacで、任意のIDEやビルドシステムで行われます。
非HTMLテンプレートもサポート。サポートされるエスケープコンテンツタイプのセットは拡張可能です。
Mustache継承スペックを介してレイアウトをサポート。
ServiceLoaderを介したフォールバックレンダーサービス拡張ポイント
出力可能な型をカスタマイズ可能(親切なtoStringを持たないクラスでのtoStringを避けるため、それ以外はコンパイラエラー)。
実行時の変数のカスタムtoStringのためのフォーマッター
トレイト的なアドオンのために生成コードに追加のimplementsインターフェースを追加 (@JStacheInterfaces)
強力なラムダサポート
Map<String, ?>のサポート
Optional<?>のサポート
JMustacheおよびHandlebarsのリストインデックス拡張(-first、-last、-indexなど)と互換性あり
JStachio自身以外に依存関係ゼロ
完全にランタイム依存のないオプションが利用可能(必要なコードはすべて生成され、実行時にjstachioさえも不要)。アノテーションプロセッサや他のゼロ依存プロジェクトでMaven shadeを使用する必要はありません。Graal VMネイティブプロジェクトでも、フットプリントを最小限にするのに役立ちます。
Spring Frameworkのファーストクラスサポート(プロジェクト自体がプラグインを提供するため、補助プロジェクトではない)
このプロジェクトの目標は最速のJavaテンプレートエンジンになることではありません!
(しかし、このreadmeが最後に更新された時点では、私の知る限り最速です)
テンプレート言語ではパフォーマンスはあまり問題になりませんが(ボトルネックになることは稀)、JStachioは非常に高速です:
https://github.com/agentgt/template-benchmark


@JStache(template = """
{{#people}}
{{message}} {{name}}! You are {{#ageInfo}}{{age}}{{/ageInfo}} years old!
{{#-last}}
That is all for now!
{{/-last}}
{{/people}}
""")
public record HelloWorld(String message, List<Person> people) implements AgeLambdaSupport {
}
public record Person(String name, LocalDate birthday) {
}
public record AgeInfo(long age, String date) {
}
public interface AgeLambdaSupport {
@JStacheLambda
default AgeInfo ageInfo(Person person) {
long age = ChronoUnit.YEARS.between(person.birthday(), LocalDate.now());
String date = person.birthday().format(DateTimeFormatter.ISO_DATE);
return new AgeInfo(age, date);
}
}
@Test
public void testPerson() throws Exception {
Person rick = new Person("Rick", LocalDate.now().minusYears(70));
Person morty = new Person("Morty", LocalDate.now().minusYears(14));
Person beth = new Person("Beth", LocalDate.now().minusYears(35));
Person jerry = new Person("Jerry", LocalDate.now().minusYears(35));
String actual = JStachio.render(new HelloWorld("Hello alien", List.of(rick, morty, beth, jerry)));
String expected = """
Hello alien Rick! You are 70 years old!
Hello alien Morty! You are 14 years old!
Hello alien Beth! You are 35 years old!
Hello alien Jerry! You are 35 years old!
That is all for now!
""";
assertEquals(expected, actual);
}
<properties>
<io.jstach.version>0.6.0-SNAPSHOT</io.jstach.version>
</properties>
...
<dependencies>
<dependency>
<groupId>io.jstach</groupId>
<artifactId>jstachio</artifactId>
<version>${io.jstach.version}</version>
</dependency>
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source> <!-- 17 is the minimum -->
<target>17</target> <!-- 17 is the minimum -->
<annotationProcessorPaths>
<path>
<groupId>io.jstach</groupId>
<artifactId>jstachio-apt</artifactId>
<version>${io.jstach.version}</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
注:アノテーションjar(jstachio-annotation)は推移的に取り込まれます。
dependencies {
implementation 'io.jstach:jstachio:VERSION'
annotationProcessor 'io.jstach:jstachio-apt:VERSION'
}
{{#name}}
<p>Name: {{.}}, Name Length is {{length}}</p>
{{/name}}
<p>Age: {{ age }}</p>
<p>Achievements:</p>
<ul>
{{#array}}
<li>{{.}}</li>
{{/array}}
</ul>
{{^array}}
<p>No achievements</p>
{{/array}}
<p>Items:</p>
<ol>
{{#list1}}
<li>{{value}}</li>
{{/list1}}
</ol>
以下のクラスを使用して、上記のテンプレートに実際のデータを提供できます。
@JStache(
// points to src/main/resources/user.mustache file
path = "user.mustache",
// or alternatively you can inline the template
template = "",
)
public record User(String name, int age, String[] array, List<Item<String>> list) {
public static class Item<T> {
private final T value;
public Item(T value) {
this.value = value;
}
T value() {
return value;
}
}
}
新しいクラスUserRendererは上記のコードから機械的に生成されます。このクラスは、実際のデータで満たされたテンプレートをレンダリングするために使用できます。テンプレートをレンダリングするには、以下のコードを使用します:
class Main {
public static void main(String[] args) throws IOException {
User user = new User("John Doe", 21, new String[] {"Knowns nothing"}, list);
StringBuilder appendable = new StringBuilder();
JStachio.render(user, appendable);
}
}
このコードを実行した結果は次のとおりです
<p>Name: John Doe, Name Length is 8</p>
<p>Age: 21</p>
<p>Achievements:</p>
<ul>
<li>Knowns nothing</li>
</ul>
<p>Items:</p>
<ol>
<li>helmet</li>
<li>shower</li>
</ol>
存在しないフィールドやレンダリング不可能な型のフィールドを参照すると、すべてコンパイル時エラーになります。これらのエラーは、Javaソースの他のエラーとともに、プロジェクトのコンパイル時に報告されます。
target/classes/user.mustache:5: error: Field not found in current context: 'age1'
<p>Age: {{ age1 }} ({{birthdate}}) </p>
^
symbol: mustache directive
location: mustache template