
Motor de plantillas Mustache para Java con seguridad de tipos, validación de plantillas en tiempo de compilación, enlace de valores estático y escape extensible para HTML y otros tipos de contenido.
Un motor de plantillas Mustache para Java con seguridad de tipos.
Las plantillas se compilan en código fuente Java legible y los enlaces de valores se verifican estáticamente.
La documentación también está en javadoc.io pero no está agregada como la anterior.
El javadoc agregado es la documentación preferida y el resto de este readme
es principalmente para fines de propaganda marketing.
Para versiones anteriores:
https://jstach.io/doc/jstachio/VERSION/apidocs
Donde VERSION es la versión que desees.
Cubierto en why_jstachio_is_better.md.
Sintaxis Mustache sin lógica (v 1.3) de Mustache.
Obtén soporte similar a JEP 430 hoy pero con aún más poder.
Las plantillas se compilan en código Java
Los enlaces de valores se verifican estáticamente.
Métodos, campos y métodos getter pueden referenciarse en las plantillas.
Mensajes de error amigables con contexto.
Configuración cero. No se requieren plugins ni ajustes. Todo se hace con javac estándar con cualquier IDE y/o sistema de construcción.
Se admiten plantillas no HTML. El conjunto de tipos de contenido de escape admitidos es extensible.
Se admiten diseños mediante la especificación de herencia de Mustache.
Punto de extensión del servicio de renderizado de respaldo mediante ServiceLoader
Personaliza los tipos permitidos que se pueden generar de lo contrario error del compilador (para evitar toString en clases que no tienen un toString amigable).
Formateador para toString personalizado de variables en tiempo de ejecución
Añade interfaces implements adicionales al código generado para complementos tipo trait (@JStacheInterfaces)
¡No es un objetivo de este proyecto ser el motor de plantillas Java más rápido!
(sin embargo, actualmente es el más rápido que conozco cuando este readme fue actualizado por última vez)
No es que el rendimiento importe mucho con los lenguajes de plantillas (rara vez es el cuello de botella) pero JStachio es muy 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 es el mínimo -->
<target>17</target> <!-- 17 es el mínimo -->
<annotationProcessorPaths>
<path>
<groupId>io.jstach</groupId>
<artifactId>jstachio-apt</artifactId>
<version>${io.jstach.version}</version>
</path>
<!-- otros procesadores de anotaciones -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
N.B. El jar de anotaciones (jstachio-annotation) se incluye 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 siguiente clase se puede usar para proporcionar datos reales para llenar la plantilla anterior.
@JStache(
// apunta al archivo src/main/resources/user.mustache
path = "user.mustache",
// o alternativamente puedes incluir la plantilla en línea
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;
}
}
}
Se generará mecánicamente una nueva clase UserRenderer con el código anterior.
Esta clase se puede usar para renderizar la plantilla con datos reales. Para renderizar la plantilla se puede usar el siguiente código:
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);
}
}
El resultado de ejecutar este 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 que no existen, o campos con tipo no renderizable, todo resulta en errores en tiempo de compilación. Estos errores se reportan en el tiempo de compilación de tu proyecto junto con otros posibles errores en fuentes 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
Consulta el proyecto test/examples para más ejemplos.
Básicamente los enums tienen claves booleanas que son el nombre del enum (Enum.name()) que se pueden usar como secciones condicionales.
Supongamos que light es un enum como:
public enum Light {
RED,
GREEN,
YELLOW
}
Puedes seleccionar condicionalmente el enum como una coincidencia de patrón:
{{#light.RED}}
STOP
{{/light.RED}}
{{#light.GREEN}}
GO
{{/light.GREEN}}
{{#light.YELLOW}}
Proceeed with caution
{{/light.YELLOW}}
JStachio es compatible con las claves de índice tanto de handlebars como de JMustache para secciones iterables.
-first es un booleano que es verdadero cuando estás en el primer elemento-last es un booleano que es verdadero cuando estás en el último elemento del iterable-index es un índice basado en uno. El primer elemento sería 1 y no 0JStachio admite llamadas de sección lambda de manera similar a JMustache. Simplemente etiqueta tus métodos
con @JStacheLambda y los modelos devueltos se usarán para renderizar el contenido de la sección lambda.
La parte superior de la pila de contexto se puede pasar a la lambda.
JStachio, a diferencia de la especificación, no admite devolver plantillas dinámicas que luego se rendericen contra la pila de contexto. Sin embargo, se puede lograr una salida dinámica cambiando el contenido de la sección lambda por parte del llamante, ya que el contenido de la sección actúa como una plantilla en línea.
La idea es crear un motor de plantillas que combine la filosofía sin lógica de mustache con la responsabilidad única y el tipado estático de Java. La verificación completa en tiempo de compilación de la sintaxis y el enlace de datos es el requisito principal.
Actualmente se genera código Java para las plantillas. El código Java generado nunca debe fallar al compilar. Si es imposible generar código Java válido a partir de alguna plantilla, se debe generar un error de compilación amigable que apunte al archivo de plantilla. Los usuarios nunca deben estar expuestos al código Java generado.
El mustache original utiliza objetos Javascript para definir el contexto de renderizado. Los campos de los objetos Javascript seleccionados se enlazan con los campos de la plantilla.
Static mustache utiliza objetos Java para definir el contexto de renderizado. El enlace de los campos de la plantilla se define y verifica en tiempo de compilación. Los campos faltantes son un error de compilación.
JStachio está bajo la licencia BSD 3 cláusulas.
Soporte potente de Lambdas
Soporte de Map<String, ?>
Soporte de Optional<?>
Compatible con las extensiones de índice de lista de JMustache y Handlebars (como -first, -last, -index)
Es, por mucho, el motor de plantillas Mustache-like más rápido de Java, así como uno de los más rápidos en general.
Cero dependencias aparte de JStachio mismo
Una opción de dependencia de tiempo de ejecución absolutamente cero está disponible (es decir, todo el código necesario se genera y ni siquiera se necesita jstachio durante el tiempo de ejecución). No es necesario usar Maven shade para procesadores de anotaciones y otros proyectos con cero dependencias. También útil para proyectos nativos de Graal VM para la huella más pequeña posible.
Soporte de primera clase para Spring Framework (es decir, el proyecto mismo proporcionará plugins en lugar de un proyecto auxiliar)