
Um mecanismo de templates Mustache para Java com segurança de tipos.
Os templates são compilados em código-fonte Java legível e os vínculos de valores são verificados estaticamente.
A documentação também está no javadoc.io, mas não é agregada como a acima.
O javadoc agregado é a documentação preferida e o restante deste readme
serve principalmente para propaganda fins de marketing.
Para versões anteriores:
https://jstach.io/doc/jstachio/VERSION/apidocs
Onde VERSION é a versão que você deseja.
Abordado em why_jstachio_is_better.md.
Sintaxe Mustache (v 1.3) sem lógica.
Obtenha suporte semelhante ao JEP 430 hoje, mas com ainda mais poder.
Templates são compilados em código Java
Os vínculos de valores são verificados estaticamente.
Métodos, campos e métodos getter podem ser referenciados em templates.
Mensagens de erro amigáveis com contexto.
Configuração zero. Nenhum plugin ou ajuste é necessário. Tudo é feito com o javac padrão, em qualquer IDE e/ou sistema de build.
Templates não HTML são suportados. O conjunto de tipos de conteúdo com escape suportados é extensível.
Layouts são suportados por meio da especificação de herança do Mustache.
Ponto de extensão de serviço de renderização fallback via ServiceLoader
Personalize os tipos permitidos que podem ser emitidos; caso contrário, erro do compilador (para evitar toString em classes que não possuem um toString amigável).
Formatador para toString personalizado de variáveis em tempo de execução
Adicione interfaces implements extras ao código gerado para complementos semelhantes a traits (@JStacheInterfaces)
Não é objetivo deste projeto ser o mecanismo de templates Java mais rápido!
(no entanto, atualmente é o mais rápido que conheço quando este readme foi atualizado pela última vez)
Não que performance importe muito com linguagens de template (raramente é o gargalo), mas o JStachio é muito rápido:
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>
N.B. O jar de anotações (jstachio-annotation) é incluído 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>
A classe a seguir pode ser usada para fornecer dados reais para preencher o template acima.
@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;
}
}
}
Uma nova classe UserRenderer será gerada mecanicamente com o código acima.
Essa classe pode ser usada para renderizar o template preenchido com dados reais. Para renderizar o template, o código a seguir pode ser usado:
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);
}
}
O resultado da execução deste código será
<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>
Referenciar campos inexistentes, ou campos com tipo não renderizável, resulta em erros de tempo de compilação. Esses erros são relatados no momento da compilação do seu projeto, juntamente com outros possíveis erros nas fontes 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
Consulte o projeto test/examples para mais exemplos.
Basicamente, enums têm chaves booleanas que são o nome do enum (Enum.name()) e podem ser usadas como seções condicionais.
Suponha que light seja um enum como:
public enum Light {
RED,
GREEN,
YELLOW
}
Você pode selecionar condicionalmente o enum como em uma correspondência de padrão:
{{#light.RED}}
STOP
{{/light.RED}}
{{#light.GREEN}}
GO
{{/light.GREEN}}
{{#light.YELLOW}}
Proceeed with caution
{{/light.YELLOW}}
O JStachio é compatível com as chaves de índice do handlebars e do JMustache para seções iteráveis.
-first é um booleano verdadeiro quando você está no primeiro item-last é um booleano verdadeiro quando você está no último item do iterável-index é um índice baseado em um. O primeiro item seria 1 e não 0O JStachio suporta chamadas de seção lambda de maneira semelhante ao JMustache. Basta marcar seus métodos
com @JStachioLambda e os modelos retornados serão usados para renderizar o conteúdo da seção lambda.
O topo da pilha de contexto pode ser passado para o lambda.
Ao contrário da especificação, o JStachio não suporta retornar templates dinâmicos que são então renderizados contra a pilha de contexto. No entanto, a saída dinâmica pode ser alcançada pelo chamador alterando o conteúdo da seção lambda, pois o conteúdo da seção atua como um template inline.
A ideia é criar um mecanismo de templates que combine a filosofia sem lógica do mustache com a responsabilidade única e a tipagem estática do Java. A verificação completa em tempo de compilação da sintaxe e da vinculação de dados é o principal requisito.
Atualmente, código Java é gerado para os templates. O código Java gerado nunca deve falhar ao compilar. Se for impossível gerar código Java válido a partir de algum template, um erro de compilação amigável apontando para o arquivo de template deve ser gerado. Os usuários nunca devem ser expostos ao código Java gerado.
O mustache original usa objetos Javascript para definir o contexto de renderização. Os campos dos objetos Javascript selecionados são vinculados aos campos do template.
O mustache estático usa objetos Java para definir o contexto de renderização. A vinculação dos campos do template é definida e verificada em tempo de compilação. Campos ausentes são erro de compilação.
JStachio é distribuído sob a licença BSD 3-Clause.
Suporte poderoso a lambdas
Suporte a Map<String, ?>
Suporte a Optional<?>
Compatível com as extensões de índice de lista do JMustache e do Handlebars (como -first, -last, -index)
É de longe o mecanismo de templates Java semelhante a Mustache mais rápido, além de um dos mais rápidos em geral.
Zero dependências além do próprio JStachio
Uma opção de dependência de tempo de execução absolutamente zero está disponível (ou seja, todo o código necessário é gerado e nem mesmo o jstachio é necessário durante a execução). Não é necessário usar o Maven shade para processadores de anotação e outros projetos com zero dependências. Também é útil para projetos nativos do Graal VM, para uma pegada mínima possível.
Suporte de primeira classe para o Spring Framework (ou seja, o próprio projeto fornecerá plugins, em vez de um projeto auxiliar)