
タイプセーフな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のリストインデックス拡張(、、など)と互換性あり
このプロジェクトの目標は最速の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
target/classes/user.mustache:5: error: Unable to render field: type error: Can't render data.birthdate expression of java.util.Date type
<p>Age: {{ age }} ({{birthdate}}) </p>
^
symbol: mustache directive
location: mustache template
詳細な例についてはtest/examplesプロジェクトを参照してください。
基本的に、enumは条件セクションとして使用できるbooleanキー(enumの名前Enum.name())を持ちます。
lightが以下のようなenumであると仮定します:
public enum Light {
RED,
GREEN,
YELLOW
}
パターンマッチのようにenumを条件付きで選択できます:
{{#light.RED}}
STOP
{{/light.RED}}
{{#light.GREEN}}
GO
{{/light.GREEN}}
{{#light.YELLOW}}
Proceeed with caution
{{/light.YELLOW}}
JStachioは、反復可能セクションのためのhandlebarsとJMustacheの両方のインデックスキーと互換性があります。
-firstは最初のアイテムにいるときにtrueになるboolean-lastは反復可能なコレクションの最後のアイテムにいるときにtrueになるboolean-indexは1ベースのインデックス。最初のアイテムは0ではなく1JStachioはJMustacheと同様の方法でラムダセクション呼び出しをサポートします。メソッドに@JStacheLambdaをタグ付けするだけで、返されたモデルがラムダセクションの内容をレンダリングするために使用されます。コンテキストスタックのトップをラムダに渡すことができます。
JStachioは仕様とは異なり、コンテキストスタックに対してレンダリングされる動的テンプレートの返却をサポートしていません。ただし、セクションの内容がインラインテンプレートとして機能するため、呼び出し元がラムダセクションの内容を変更することで動的な出力を実現できます。
アイデアは、mustacheのロジックレスの哲学とJavaの単一責任および静的型付けを組み合わせたテンプレートエンジンを作成することです。構文とデータバインディングの完全なコンパイル時チェックが主な要件です。
現在、テンプレートからJavaコードが生成されます。生成されたJavaコードは決してコンパイルに失敗しないはずです。あるテンプレートから有効なJavaコードを生成できない場合は、テンプレートファイルを指し示す親切なコンパイル時エラーが生成されるべきです。ユーザーは生成されたJavaコードに晒されるべきではありません。
元のmustacheはレンダリングコンテキストを定義するためにJavascriptオブジェクトを使用します。選択されたJavascriptオブジェクトのフィールドはテンプレートフィールドにバインドされます。
Static mustacheはレンダリングコンテキストを定義するためにJavaオブジェクトを使用します。テンプレートフィールドのバインディングはコンパイル時に定義およびチェックされます。欠落したフィールドはコンパイル時エラーになります。
JStachioはBSD 3条項ライセンスの下で提供されています。
-first-last-indexJStachio自身以外に依存関係ゼロ
完全にランタイム依存のないオプションが利用可能(必要なコードはすべて生成され、実行時にjstachioさえも不要)。アノテーションプロセッサや他のゼロ依存プロジェクトでMaven shadeを使用する必要はありません。Graal VMネイティブプロジェクトでも、フットプリントを最小限にするのに役立ちます。
Spring Frameworkのファーストクラスサポート(プロジェクト自体がプラグインを提供するため、補助プロジェクトではない)