
Moteur de templating Mustache Java type-safe avec validation de templates à la compilation, liaison de valeurs statique et échappement extensible pour HTML et autres types de contenu.
Un moteur de templates Java Mustache type-sûr.
Les templates sont compilés en code source Java lisible et les liaisons de valeurs sont vérifiées statiquement.
La documentation est également sur javadoc.io mais n'est pas agrégée comme ci-dessus.
La javadoc agrégée est la documentation de référence et le reste de ce readme
sert principalement à des fins de propagande marketing.
Pour les versions précédentes :
https://jstach.io/doc/jstachio/VERSION/apidocs
Où VERSION est la version souhaitée.
Traité dans why_jstachio_is_better.md.
Syntaxe Mustache (v 1.3) sans logique.
Profitez dès aujourd'hui d'un support de type JEP 430 mais avec encore plus de puissance.
Les templates sont compilés en code Java
Les liaisons de valeurs sont vérifiées statiquement.
Les méthodes, les champs et les méthodes getter peuvent être référencés dans les templates.
Messages d'erreur conviviaux avec contexte.
Zéro configuration. Aucun plugin ni ajustement requis. Tout est fait avec le javac standard avec n'importe quel IDE et/ou système de build.
Les templates non-HTML sont pris en charge. L'ensemble des types de contenu d'échappement pris en charge est extensible.
Les layouts sont pris en charge via la spécification d'héritage de Mustache.
Point d'extension du service de rendu de secours via ServiceLoader
Personnalisez les types autorisés à être générés en sortie, sinon erreur du compilateur (pour éviter toString sur des classes qui n'ont pas un toString convivial).
Formateur pour un toString personnalisé des variables à l'exécution
Ajoutez des interfaces implements supplémentaires au code généré pour des extensions de type trait (@JStacheInterfaces)
Prise en charge puissante des lambdas
Prise en charge de Map<String, ?>
Prise en charge de Optional<?>
Compatible avec les extensions d'index de liste de JMustache et Handlebars (comme -first, -last, -index)
C'est de loin le moteur de templates Java de type Mustache le plus rapide, et également l'un des plus rapides en général.
Zéro dépendance en dehors de JStachio lui-même
Une option de dépendance runtime absolument nulle est disponible (c'est-à-dire que tout le code nécessaire est généré et même jstachio n'est pas requis à l'exécution). Pas besoin d'utiliser Maven shade pour les processeurs d'annotations et autres projets zéro dépendance. Également utile pour les projets natifs Graal VM afin d'avoir une empreinte minimale.
Prise en charge de première classe pour Spring Framework (c'est-à-dire que le projet lui-même fournira des plugins, contrairement à un projet auxiliaire)
Ce projet n'a pas pour objectif d'être le moteur de templates Java le plus rapide !
(cependant, c'est actuellement le plus rapide que je connaisse au moment de la dernière mise à jour de ce readme)
Non pas que la performance importe beaucoup avec les langages de templating (ce n'est que rarement le goulot d'étranglement) mais JStachio est très rapide :


@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>
N.B. Le jar d'annotations (jstachio-annotation) est inclus transitivement
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>
La classe suivante peut être utilisée pour fournir les données réelles afin de remplir le template ci-dessus.
@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;
}
}
}
Une nouvelle classe UserRenderer sera générée mécaniquement avec le code ci-dessus.
Cette classe peut être utilisée pour rendre le template rempli avec les données réelles. Pour rendre le template, le code suivant peut être utilisé :
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);
}
}
Le résultat de l'exécution de ce code sera
<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>
La référence à des champs inexistants, ou à des champs avec un type non rendable, entraîne des erreurs de compilation. Ces erreurs sont signalées au moment de la compilation de votre projet, en plus des autres erreurs possibles dans les sources 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
Voir le projet test/examples pour plus d'exemples.
En gros, les enums ont des clés booléennes qui sont le nom de l'enum (Enum.name()) et qui peuvent être utilisées comme sections conditionnelles.
Supposons que light soit une enum comme :
public enum Light {
RED,
GREEN,
YELLOW
}
Vous pouvez sélectionner conditionnellement l'enum comme un pattern matching :
{{#light.RED}}
STOP
{{/light.RED}}
{{#light.GREEN}}
GO
{{/light.GREEN}}
{{#light.YELLOW}}
Proceeed with caution
{{/light.YELLOW}}
JStachio est compatible avec les clés d'index de handlebars et de JMustache pour les sections itérables.
-first est un booléen vrai lorsque vous êtes sur le premier élément-last est un booléen vrai lorsque vous êtes sur le dernier élément de l'itérable-index est un index basé sur un. Le premier élément serait 1 et non 0JStachio prend en charge les appels de section lambda de manière similaire à JMustache. Il suffit de marquer vos méthodes avec @JStacheLambda et les modèles retournés seront utilisés pour rendre le contenu de la section lambda. Le sommet de la pile de contexte peut être passé à la lambda.
Contrairement à la spécification, JStachio ne prend pas en charge le retour de templates dynamiques qui seraient ensuite rendus avec la pile de contexte. Cependant, une sortie dynamique peut être obtenue par l'appelant en modifiant le contenu de la section lambda, car le contenu de la section agit comme un template en ligne.
L'idée est de créer un moteur de templates combinant la philosophie sans logique de mustache avec la responsabilité unique et le typage statique de Java. La vérification complète au moment de la compilation de la syntaxe et de la liaison des données est l'exigence principale.
Actuellement, du code Java est généré pour les templates. Le code Java généré ne doit jamais échouer à la compilation. S'il est impossible de générer du code Java valide à partir d'un template, une erreur de compilation conviviale pointant vers le fichier template doit être générée. Les utilisateurs ne doivent jamais être exposés au code Java généré.
Le mustache d'origine utilise des objets Javascript pour définir le contexte de rendu. Les champs des objets Javascript sélectionnés sont liés aux champs du template.
Le mustache statique utilise des objets Java pour définir le contexte de rendu. La liaison des champs du template est définie et vérifiée au moment de la compilation. Les champs manquants sont des erreurs de compilation.
JStachio est sous licence BSD 3-clause.