
Type-safe motore di templating Mustache per Java con validazione dei template in fase di compilazione, binding statico dei valori ed escaping estensibile per HTML e altri tipi di contenuto.
Un motore di templating Java type-safe per Mustache.
I template vengono compilati in codice sorgente Java leggibile e i binding dei valori vengono controllati staticamente.
La documentazione è disponibile anche su javadoc.io ma non è aggregata come quella sopra.
La javadoc aggregata è la documentazione preferita e il resto di questo readme
è principalmente a scopo propagandistico di marketing.
Per le versioni precedenti:
https://jstach.io/doc/jstachio/VERSION/apidocs
Dove VERSION è la versione che desideri.
Trattato in why_jstachio_is_better.md.
Sintassi Mustache (v 1.3) senza logica.
Ottieni oggi un supporto simile a JEP 430, ma con ancora più potenza.
I template vengono compilati in codice Java
I binding dei valori vengono controllati staticamente.
Metodi, campi e metodi getter possono essere referenziati nei template.
Messaggi di errore amichevoli con contesto.
Zero configurazione. Non sono richiesti plugin o modifiche. Tutto viene fatto con javac standard con qualsiasi IDE e/o sistema di build.
Sono supportati template non-HTML. Il set di tipi di contenuto con escaping supportati è estensibile.
I layout sono supportati tramite la specifica di ereditarietà di Mustache.
Punto di estensione del servizio di rendering fallback tramite ServiceLoader
Personalizza i tipi consentiti che possono essere emessi, altrimenti errore del compilatore (per evitare toString su classi che non hanno un toString leggibile).
Formatter per un toString personalizzato delle variabili a runtime.
Aggiungi ulteriori interfacce implements al codice generato per componenti aggiuntivi simili a trait (@JStacheInterfaces)
Potente supporto alle lambda
Supporto a Map<String, ?>
Supporto a Optional<?>
Compatibile con le estensioni degli indici di lista di JMustache e Handlebars (come -first, -last, -index)
È di gran lunga il motore di template Java simile a Mustache più veloce, nonché uno dei più veloci in generale.
Zero dipendenze oltre a JStachio stesso
È disponibile un'opzione con zero dipendenze runtime assolute (ovvero tutto il codice necessario viene generato e durante il runtime non serve nemmeno jstachio). Non c'è bisogno di usare Maven shade per gli annotation processor e altri progetti zero dipendenze. Utile anche per progetti native di Graal VM per un footprint il più minimo possibile.
Supporto di prima classe per Spring Framework (nel senso che il progetto stesso fornirà i plugin, a differenza di un progetto ausiliario)
Non è un obiettivo di questo progetto essere il motore di template Java più veloce!
(tuttavia, al momento dell'ultimo aggiornamento di questo readme, è il più veloce che io conosca)
Non che le prestazioni contino molto con i linguaggi di templating (raramente sono il collo di bottiglia), ma JStachio è molto veloce:


@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. Il jar delle annotazioni (jstachio-annotation) viene incluso transitivamente
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 seguente classe può essere usata per fornire i dati reali da inserire nel template sopra.
@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;
}
}
}
La nuova classe UserRenderer verrà generata meccanicamente con il codice sopra.
Questa classe può essere usata per renderizzare il template riempito con dati reali. Per renderizzare il template si può usare il seguente codice:
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);
}
}
Il risultato dell'esecuzione di questo codice sarà
<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>
Il riferimento a campi inesistenti, o a campi con tipo non renderizzabile, comporta errori in fase di compilazione. Questi errori vengono segnalati durante la compilazione del progetto insieme ad altri possibili errori nei sorgenti 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
Vedi il progetto test/examples per ulteriori esempi.
In pratica gli enum hanno chiavi booleane che sono il nome dell'enum (Enum.name()) e possono essere usate come sezioni condizionali.
Supponiamo che light sia un enum come:
public enum Light {
RED,
GREEN,
YELLOW
}
Puoi selezionare condizionalmente l'enum come in un pattern match:
{{#light.RED}}
STOP
{{/light.RED}}
{{#light.GREEN}}
GO
{{/light.GREEN}}
{{#light.YELLOW}}
Proceeed with caution
{{/light.YELLOW}}
JStachio è compatibile con le chiavi indice sia di handlebars che di JMustache per le sezioni iterabili.
-first è un booleano vero quando sei sul primo elemento-last è un booleano vero quando sei sull'ultimo elemento dell'iterabile-index è un indice a base uno. Il primo elemento sarebbe 1 e non 0JStachio supporta le chiamate a sezioni lambda in modo simile a JMustache. Basta annotare i propri metodi con @JStacheLambda e i modelli restituiti verranno usati per renderizzare il contenuto della sezione lambda. La cima dello stack di contesto può essere passata alla lambda.
A differenza della specifica, JStachio non supporta la restituzione di template dinamici che vengono poi renderizzati contro lo stack di contesto. Tuttavia, l'output dinamico può essere ottenuto dal chiamante modificando il contenuto della sezione lambda, poiché il contenuto della sezione funge da template inline.
L'idea è creare un motore di templating che combini la filosofia logicless di mustache con la single responsibility e la tipizzazione statica di Java. Il controllo completo in fase di compilazione di sintassi e data-binding è il requisito principale.
Attualmente il codice Java viene generato per i template. Il codice Java generato non dovrebbe mai fallire la compilazione. Se è impossibile generare codice Java valido da un template, dovrebbe essere generato un errore di compilazione amichevole che indica il file del template. Gli utenti non dovrebbero mai essere esposti al codice Java generato.
Il mustache originale usa oggetti Javascript per definire il contesto di rendering. I campi degli oggetti Javascript selezionati vengono collegati ai campi del template.
Il mustache statico usa oggetti Java per definire il contesto di rendering. Il binding dei campi del template viene definito e controllato in fase di compilazione. I campi mancanti sono un errore di compilazione.
JStachio è sotto licenza BSD a 3 clausole.