tessl install tessl/maven-io-quarkus--quarkus-qute@3.30.0Offer templating support for web, email, etc in a build time, type-safe way
Qute is a powerful, type-safe templating engine for the Quarkus framework. This document provides a comprehensive reference of all template syntax features, operators, section helpers, and virtual methods available in Qute templates.
Value expressions are the fundamental building blocks of Qute templates, allowing you to output dynamic data and access object properties.
Basic Syntax:
{name}
{item.title}
{user.getFullName()}
{product.price}Expression Types:
{name} - Outputs the value of a variable{user.email} - Accesses object properties via getters or fields{user.getAge()} - Invokes methods on objects{order.customer.address.city} - Chains property/method access{items.0} or {items.get(0)} - Access elements by index{map.keyName} or {map.get('key')} - Access map entriesLiterals:
{true}
{false}
{null}
{42}
{3.14}
{'string literal'}
{"another string"}Namespace Access:
Expressions can use namespaces to access global data or utilities:
{data:colors}
{inject:bean}
{config:propertyName}
{msg:messageKey}Qute supports a comprehensive set of operators for expressions and conditionals.
<!-- AND operator -->
{#if user.active && user.verified}
Active and verified
{/if}
{#if condition1 and condition2}
Both true
{/if}
<!-- OR operator -->
{#if user.admin || user.moderator}
Has privileges
{/if}
{#if condition1 or condition2}
At least one true
{/if}
<!-- NOT operator -->
{#if !user.banned}
Not banned
{/if}
{#if !item.isEmpty()}
Has items
{/if}<!-- Equality -->
{#if age == 18}
{#if status eq 'ACTIVE'}
{#if user is admin}
<!-- Inequality -->
{#if count != 0}
{#if status ne 'INACTIVE'}
<!-- Greater than -->
{#if score > 100}
{#if value gt threshold}
<!-- Greater than or equal -->
{#if age >= 18}
{#if count ge minimum}
<!-- Less than -->
{#if price < 50}
{#if value lt maximum}
<!-- Less than or equal -->
{#if stock <= 10}
{#if count le limit}Note: Comparison operators work with:
<!-- Addition -->
{count + 5}
{count.plus(5)}
<!-- Subtraction -->
{total - discount}
{total.minus(discount)}
<!-- Multiplication (via extensions) -->
{price * quantity}
<!-- Division (via extensions) -->
{total / count}
<!-- Modulo -->
{number mod 2}
{number.mod(2)}
<!-- String concatenation -->
{firstName + ' ' + lastName}
{str:concat(firstName, ' ', lastName)}The elvis operator provides a default value when the expression is null or not found:
<!-- Returns 'Guest' if name is null -->
{name ?: 'Guest'}
<!-- Alternative syntax -->
{name or 'Guest'}
{name.or('Guest')}
<!-- Works with Optional -->
{optionalValue ?: 'default'}<!-- Condition ? true-value : false-value -->
{user.active ? 'Active' : 'Inactive'}
<!-- Using method names -->
{user.active.ifTruthy('Active').or('Inactive')}<!-- Returns empty list if items is null -->
{items.orEmpty}
<!-- Prevents null pointer exceptions -->
{user.address.orEmpty.city}
<!-- Chain with elvis operator -->
{user.address.city ?: 'Unknown'}Section helpers are special template constructs that control flow, iteration, and template composition.
The {#if} section allows conditional rendering based on expressions.
Basic Usage:
{#if user}
User is logged in
{/if}
{#if count > 0}
There are {count} items
{/if}With {#else}:
{#if user.isPremium()}
<div class="premium-badge">Premium Member</div>
{#else}
<div class="standard-badge">Standard Member</div>
{/if}With {#else if}:
{#if score >= 90}
Grade: A
{#else if score >= 80}
Grade: B
{#else if score >= 70}
Grade: C
{#else}
Grade: F
{/if}Complex Conditions:
{#if user.active && user.verified && !user.suspended}
Full access granted
{/if}
{#if (age >= 18 && age < 65) || hasSpecialPermission}
Eligible
{/if}Falsy Values:
The following values are considered "falsy" in conditions:
nullfalse""The {#for} and {#each} sections iterate over collections, arrays, maps, streams, and integer ranges.
Basic Iteration:
{#for item in items}
<li>{item.name}</li>
{/for}
{#each product in products}
<div>{product.title} - ${product.price}</div>
{/each}Custom Alias:
{#for user in users}
{user.name}
{/for}
<!-- Iterating without 'in' keyword (using default 'it' alias) -->
{#each items}
{it.name}
{/each}Iteration Metadata:
By default, metadata is accessible with the alias followed by underscore:
{#for item in items}
<div>
Item #{item_count}: {item.name}
{#if item_isFirst}(First){/if}
{#if item_isLast}(Last){/if}
{#if item_hasNext}, {/if}
</div>
{/for}Available Metadata Properties:
{alias_count} - 1-based iteration count (1, 2, 3, ...){alias_index} - 0-based iteration index (0, 1, 2, ...){alias_hasNext} - true if there are more elements{alias_isLast} - true if this is the last element{alias_isFirst} - true if this is the first element (index == 0){alias_odd} - true if count is odd{alias_isOdd} - true if count is odd{alias_even} - true if count is even{alias_isEven} - true if count is even{alias_indexParity} - "odd" or "even"With {#else} Block:
The {#else} block executes when the iterable is empty or null:
{#for item in items}
<li>{item.name}</li>
{#else}
<p>No items found</p>
{/for}Iterating Over Different Types:
<!-- Collections and Lists -->
{#each items}
{it}
{/each}
<!-- Arrays -->
{#for element in arrayData}
{element}
{/for}
<!-- Maps (iterates over entries) -->
{#for entry in map}
{entry.key}: {entry.value}
{/for}
<!-- Integer range -->
{#for i in 5}
Iteration {i}
{/for}
<!-- Long range -->
{#for n in 10L}
Number {n}
{/for}
<!-- Streams -->
{#each stream}
{it.data}
{/each}
<!-- Iterators -->
{#for item in iterator}
{item}
{/for}The {#with} section changes the current context object for its body.
Basic Usage:
{#with user}
Name: {name}
Email: {email}
Age: {age}
{/with}Accessing Nested Objects:
{#with order.customer}
<h2>Customer: {name}</h2>
{#with address}
<p>{street}, {city}, {zipCode}</p>
{/with}
{/with}Note: Inside a {#with} block, this refers to the context object.
The {#let} and {#set} sections create local variables within their scope.
Basic Usage:
{#let name='John' age=30}
Hello {name}, you are {age} years old.
{/let}
{#set fullName=user.firstName + ' ' + user.lastName}
Welcome {fullName}!
{/set}Multiple Variables:
{#let
x=10
y=20
sum=x + y
}
{x} + {y} = {sum}
{/let}Default Values with ? Suffix:
Variables with a ? suffix only get assigned if they don't already exist or are null:
{#set greeting?='Hello'}
{greeting}
{/set}Without End Tag:
Both {#set} and {#let} support optional end tags:
{#set currentPage=5 /}
{#let items=data.items /}The {#include} section includes another template, optionally passing parameters and overriding blocks.
Basic Inclusion:
{#include 'header.html' /}
{#include template='footer.html' /}With Parameters:
{#include 'user-card.html' user=currentUser showEmail=true /}
<!-- Parameters become available in the included template -->Fragment Inclusion:
<!-- Include specific fragment from template -->
{#include 'common.html$navigation' /}
<!-- Include fragment from current template -->
{#include '$sidebar' /}Dynamic Template ID:
{#include _id=templateName /}
{#include _id='templates/' + type + '.html' /}Isolated Context:
By default, included templates have access to the parent context. Use _isolated to prevent this:
{#include 'isolated-template.html' _isolated /}
{#include 'isolated-template.html' _isolated=true data=myData /}Unisolated (Explicit):
{#include 'template.html' _unisolated /}With Block Overrides:
{#include 'base.html'}
{#header}
<h1>Custom Header</h1>
{/header}
{#content}
<p>Custom content for this page</p>
{/content}
{/include}The {#insert} section defines insertion points in templates that can be overridden by including templates.
In Base Template:
<!DOCTYPE html>
<html>
<head>
{#insert title}
<title>Default Title</title>
{/insert}
</head>
<body>
{#insert header}
<h1>Default Header</h1>
{/insert}
{#insert content}
<p>Default content</p>
{/insert}
{#insert footer}
<footer>Default Footer</footer>
{/insert}
</body>
</html>In Including Template:
{#include 'base.html'}
{#title}
<title>My Custom Page</title>
{/title}
{#content}
<h2>Welcome to My Page</h2>
<p>This content overrides the default.</p>
{/content}
{/include}Custom Names:
<!-- Base template -->
{#insert name='sidebar'}
Default sidebar content
{/insert}
<!-- Including template -->
{#include 'base.html'}
{#sidebar}
Custom sidebar
{/sidebar}
{/include}Default Block:
The main block content of {#insert} serves as the default when not overridden.
The {#fragment} section defines reusable template fragments that can be rendered separately.
Basic Fragment:
{#fragment id='user-card'}
<div class="card">
<h3>{name}</h3>
<p>{email}</p>
</div>
{/fragment}Accessing Fragments:
Template template = engine.getTemplate("users.html");
Fragment fragment = template.getFragment("user-card");
String rendered = fragment.data("name", "John", "email", "john@example.com").render();Hidden/Capture Fragments:
Fragments that should not render in the main template:
{#fragment id='helper' _hidden}
This won't render unless specifically requested
{/fragment}
{#capture id='reusable'}
Capture is an alias for hidden fragments
{/capture}Conditional Rendering:
{#fragment id='notification' rendered=showNotification}
<div class="notification">{message}</div>
{/fragment}Including Fragments:
{#include '$my-fragment' /}
{#include 'other-template.html$fragment-id' /}The {#when} (alias {#switch}) section provides pattern matching similar to switch statements.
Basic Usage:
{#when status}
{#is 'ACTIVE'}
<span class="badge-success">Active</span>
{#is 'PENDING'}
<span class="badge-warning">Pending</span>
{#is 'INACTIVE'}
<span class="badge-danger">Inactive</span>
{#else}
<span class="badge-secondary">Unknown</span>
{/when}Alternative Syntax with {#case}:
{#switch userRole}
{#case 'ADMIN'}
<p>Administrator access</p>
{#case 'MODERATOR'}
<p>Moderator access</p>
{#case 'USER'}
<p>Standard user access</p>
{#else}
<p>Guest access</p>
{/switch}Comparison Operators:
{#when age}
{#is gt 65}
Senior
{#is ge 18}
Adult
{#is lt 18}
Minor
{/when}
{#when score}
{#is >= 90}
Grade A
{#is >= 80}
Grade B
{#is < 60}
Grade F
{/when}IN Operator:
{#when role}
{#is in 'ADMIN' 'SUPERUSER' 'ROOT'}
Administrator
{#is in 'MODERATOR' 'EDITOR'}
Content Manager
{#else}
Regular User
{/when}NOT IN Operator:
{#when country}
{#is !in 'US' 'CA' 'MX'}
International shipping
{#else}
Domestic shipping
{/when}
{#when status}
{#is ni 'DELETED' 'ARCHIVED'}
Active record
{/when}Enum Matching:
For enum values, use the constant name:
{#when orderStatus}
{#is PENDING}
Order is being processed
{#is SHIPPED}
Order has been shipped
{#is DELIVERED}
Order delivered
{/when}Operators Available:
is, eq, == (default if no operator specified)ne, !=, notgt, >ge, >=lt, <le, <=in!in, niThe {#eval} section parses and evaluates a string as a template at runtime.
Basic Usage:
{#eval template='Hello {name}!' /}
{#set dynamicTemplate='<p>Welcome {user.name}!</p>' /}
{#eval template=dynamicTemplate /}With Parameters:
{#eval template='Hello {firstName} {lastName}!' firstName='John' lastName='Doe' /}Template from Variable:
{#eval template=templateString param1=value1 param2=value2 /}Use Cases:
Note: The evaluated template string is parsed by the Qute engine and has access to all passed parameters.
Comments are ignored during rendering and can be used for documentation or temporarily disabling code.
Single-line Comments:
{! This is a comment !}
{! TODO: Add error handling here !}Multi-line Comments:
{!
This is a multi-line comment
that spans several lines
and will not be rendered
!}Commenting Out Code:
{!
{#if user}
<div>This code is temporarily disabled</div>
{/if}
!}Note: Comments are completely removed during parsing and do not appear in the rendered output.
By default, Qute escapes output based on the template variant (HTML, XML, etc.) to prevent XSS attacks.
Default Escaping (HTML):
{message}
<!-- If message = "<script>alert('xss')</script>" -->
<!-- Output: <script>alert('xss')</script> -->Raw/Unsafe Output:
Use the raw or safe virtual methods to output unescaped content:
{htmlContent.raw}
{htmlContent.safe}
{htmlContent|raw}
{htmlContent|safe}Example:
{#let html='<strong>Bold text</strong>'}
Escaped: {html}
<!-- Output: <strong>Bold text</strong> -->
Raw: {html.raw}
<!-- Output: <strong>Bold text</strong> -->
{/let}Using RawString Class:
// In Java code
template.data("content", new RawString("<p>Safe HTML</p>"));Warning: Only use .raw or .safe with trusted content to avoid XSS vulnerabilities.
Virtual methods are special methods available on all objects in templates, providing utility functions and transformations.
Returns an empty list if the value is null or not found:
{#for item in items.orEmpty}
{item.name}
{#else}
No items
{/for}
<!-- Prevents errors when items is null -->
{items.orEmpty.size}Returns the first parameter if the base is truthy, otherwise returns NotFound (useful with elvis operator):
{user.active.ifTruthy('Yes').or('No')}
{count.ifTruthy('Has items').or('Empty')}
<!-- Ternary operator alternative -->
{user.isPremium() ? 'Premium' : 'Standard'}Provides a default value:
{name.or('Unknown')}
{user.email.or('no-email@example.com')}
{optionalValue.or(defaultValue)}Returns the object itself:
{#with user}
User object: {this}
Name: {name}
{/with}Outputs content without escaping:
{htmlContent.raw}
{markup.safe}size - Returns collection size:
{items.size}
{#if users.size > 10}Too many users{/if}isEmpty / empty - Checks if collection is empty:
{#if items.isEmpty}
No items
{/if}
{#if !cart.empty}
Cart has items
{/if}contains - Checks if collection contains element:
{#if roles.contains('ADMIN')}
Admin user
{/if}get(index) - Gets element at index:
{items.get(0)}
{users.get(selectedIndex)}Index access (via extension):
{items.0}
{items.1}
{list.42}first - Gets first element:
{items.first}
{#if list.first.name == 'Alpha'}First item is Alpha{/if}last - Gets last element:
{items.last}
{users.last.email}reversed - Returns reverse iterator:
{#for item in items.reversed}
{item.name}
{/for}take(n) - Returns first n elements:
{#for item in items.take(5)}
{item}
{/for}takeLast(n) - Returns last n elements:
{#for item in items.takeLast(3)}
{item}
{/for}keys / keySet - Returns map keys:
{#for key in map.keys}
{key}
{/for}values - Returns map values:
{#for value in map.values}
{value}
{/for}entrySet - Returns map entries:
{#for entry in map.entrySet}
{entry.key}: {entry.value}
{/for}size - Returns map size:
{map.size}empty / isEmpty - Checks if map is empty:
{#if !map.empty}
Map has entries
{/if}get(key) - Gets value for key:
{map.get('username')}containsKey(key) - Checks key existence:
{#if map.containsKey('email')}
Email exists
{/if}key - Returns entry key:
{entry.key}value - Returns entry value:
{entry.value}Concatenation:
{firstName + ' ' + lastName}
{str:concat(firstName, ' ', lastName)}Format:
{'Hello %s'.fmt(name)}
{str:fmt('Total: $%.2f', price)}Join:
{str:join(', ', item1, item2, item3)}Arithmetic:
{count.plus(5)}
{count + 5}
{total.minus(discount)}
{total - discount}
{value.mod(2)}{time:format(now, 'yyyy-MM-dd')}
{time:format(timestamp, 'HH:mm:ss', locale)}
{now.format('yyyy-MM-dd HH:mm')}Refers to the current context object:
{#with user}
{this.name}
{name}
{/with}Access CDI beans (Quarkus integration):
{inject:beanName.method()}Access configuration properties (Quarkus integration):
{config:propertyName}
{config:['app.version']}
{config:property('database.url')}Access internationalized messages (Quarkus integration):
{msg:greeting}
{msg:welcomeMessage(user.name)}Default namespace for template data:
{data:items}
{data:user.name}Qute supports type-safe templates in Quarkus applications using compile-time validation.
Parameter Declarations:
{@org.acme.User user}
{@java.lang.String title}
{@java.util.List<org.acme.Item> items}
<!DOCTYPE html>
<html>
<head><title>{title}</title></head>
<body>
<h1>Welcome {user.name}!</h1>
{#for item in items}
<div>{item.title}</div>
{/for}
</body>
</html>@CheckedTemplate Annotation:
@CheckedTemplate
public class Templates {
public static native TemplateInstance users(List<User> users);
public static native TemplateInstance product(Product product, boolean showDetails);
}
// Usage
Templates.users(userList).render();Benefits:
{user.address.city.orEmpty}
{user?.address?.city ?: 'Unknown'}
{customer.orders.first.items.size}{user.hasRole('ADMIN')}
{product.calculatePrice(quantity, discount)}
{string.substring(0, 10)}// Template method with named parameters
public native TemplateInstance greet(String name, String title);{greet(name='John', title='Mr.')}{(x + y) * z}
{items.size > 0 && items.first.active}
{user.role == 'ADMIN' || user.role == 'MODERATOR'}Qute automatically removes standalone lines (lines containing only section tags) to produce clean output.
Standalone Lines Removed:
{#if user}
Content here
{/if}Output has no extra blank lines from the tag lines.
Disable Standalone Line Removal:
Configure the engine:
Engine.builder()
.removeStandaloneLines(false)
.build();Or in Quarkus configuration:
quarkus.qute.remove-standalone-lines=falseTemplates can have variants based on content type, locale, and encoding.
Setting Variant:
template.instance()
.setVariant(Variant.forContentType("text/html"))
.render();Content Types:
text/html - HTML with automatic escapingtext/plain - Plain text, no escapingtext/xml - XML with escapingapplication/json - JSON formatLocale Support:
template.instance()
.setLocale(Locale.FRENCH)
.render();Qute provides detailed error messages with template locations.
Common Errors:
Strict vs. Lenient Rendering:
By default, Qute uses strict rendering (throws exceptions). Configure lenient mode:
Engine.builder()
.strictRendering(false)
.build();Using orEmpty to Prevent Errors:
{#for item in maybeNullList.orEmpty}
{item}
{/for}<!-- Wrong: Throws exception if name is null -->
{name}
<!-- Correct: Provides default for null -->
{name ?: 'Guest'}<!-- Wrong: Throws exception if items is null -->
{#for item in items}
{item}
{/for}
<!-- Correct: Use orEmpty -->
{#for item in items.orEmpty}
{item}
{#else}
No items found
{/for}<!-- Wrong: May not evaluate as expected -->
{#if user.active && user.verified || user.admin}
<!-- Evaluates as: (user.active && user.verified) || user.admin -->
{/if}
<!-- Correct: Use parentheses for clarity -->
{#if (user.active && user.verified) || user.admin}
Access granted
{/if}<!-- Wrong: HTML is escaped -->
{htmlContent}
<!-- Output: <strong>Bold</strong> -->
<!-- Correct: Use raw for trusted content -->
{htmlContent.raw}
<!-- Output: <strong>Bold</strong> --><!-- Wrong: Nested if statements -->
{#if status == 'ACTIVE'}
Active
{#else}
{#if status == 'PENDING'}
Pending
{#else}
Inactive
{/if}
{/if}
<!-- Correct: Use when/switch -->
{#when status}
{#is 'ACTIVE'}Active{/is}
{#is 'PENDING'}Pending{/is}
{#else}Inactive{/else}
{/when}{! Empty strings are falsy !}
{#if emptyString}
Won't render
{/if}
{! But different from null !}
{emptyString ?: 'default'} {! Renders empty string, not 'default' !}
{nullValue ?: 'default'} {! Renders 'default' !}{! Zero is falsy in conditions !}
{#if count}
Has items
{#else}
No items {! Renders when count is 0 !}
{/if}
{! But zero is a valid value !}
{count ?: 'N/A'} {! Renders '0', not 'N/A' !}{! Both work for getters !}
{user.getName()} {! Method call !}
{user.name} {! Property access (calls getName()) !}
{! For methods with parameters, must use call syntax !}
{user.hasRole('ADMIN')} {! Must use () !}{! Access fragment from current template !}
{#include '$myFragment' /}
{! Access fragment from other template !}
{#include 'other-template.html$myFragment' /}
{! Pass parameters to fragment !}
{#include '$myFragment' param1=value1 param2=value2 /}{! Expressions in section parameters are evaluated !}
{#if items.size > (limit * 2)}
Too many items
{/if}
{#for item in items.take(maxItems)}
{item}
{/for}
{#let calculated=price * quantity * (1 + taxRate)}
Total: {calculated}
{/let}{! Deeply nested sections !}
{#if user}
{#if user.orders}
{#for order in user.orders}
{#if order.items}
{#for item in order.items}
{item.name}
{/for}
{/if}
{/for}
{/if}
{/if}
{! Same with null-safe navigation !}
{#for order in user.orders.orEmpty}
{#for item in order.items.orEmpty}
{item.name}
{/for}
{/for}{! Eval with null template string !}
{#eval template=null /} {! Renders nothing !}
{! Eval with empty template !}
{#eval template='' /} {! Renders nothing !}
{! Eval with missing parameters !}
{#eval template='Hello {name}!' /} {! name resolves from outer scope !}
{! Eval with parameter masking !}
{#let name='Outer'}
{#eval template='Hello {name}!' name='Inner' /} {! Outputs: Hello Inner! !}
{/let}{! Include non-existent template !}
{#include 'missing.html' /} {! Throws TemplateException !}
{! Include with empty data !}
{#include 'template.html' /} {! Has access to parent context !}
{! Isolated include without data !}
{#include 'template.html' _isolated /} {! Template has no data access !}
{! Include with fragment from non-existent template !}
{#include 'missing.html$fragment' /} {! Throws TemplateException !}{! When with null value !}
{#when null}
{#is 'test'}Never matches{/is}
{#else}Matched{/else} {! Renders this !}
{/when}
{! When with multiple 'is' matching same value !}
{#when value}
{#is 'A'}First match{/is}
{#is 'A'}Never reached{/is} {! First match wins !}
{/when}
{! Empty when !}
{#when value}
{/when} {! Valid but produces no output !}{#let} over complex inline expressions for readability.orEmpty when iterating over potentially null collections.raw for trusted content{#include} with _isolated when you want complete isolation from parent context{#when} for multi-way branching instead of nested {#if} statementsitem_isLast) for conditional formatting.size, .isEmpty, .contains for cleaner templatesQute.enableCache() or configure Quarkus caching{#include} judiciously - Each inclusion has overheadbase.html:
<!DOCTYPE html>
<html>
<head>
{#insert title}<title>Default</title>{/insert}
</head>
<body>
<header>{#insert header}Default Header{/insert}</header>
<main>{#insert content}Default Content{/insert}</main>
<footer>{#insert footer}Default Footer{/insert}</footer>
</body>
</html>page.html:
{#include 'base.html'}
{#title}<title>My Page</title>{/title}
{#content}
<h1>Welcome</h1>
<p>Page content here</p>
{/content}
{/include}{! user-card.html !}
{@org.acme.User user}
<div class="card">
<img src="{user.avatar}" alt="{user.name}">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
{! Usage in another template !}
{#for user in users}
{#include 'user-card.html' user=user /}
{/for}<div class="item {#if item.active}active{/if} {#if item.featured}featured{/if}">
{item.name}
</div>
<span class="{item.status.ifTruthy('badge-success').or('badge-default')}">
{item.status ?: 'N/A'}
</span>{#let
page=currentPage
totalPages=items.size / pageSize
}
<nav>
{#if page > 1}
<a href="?page={page - 1}">Previous</a>
{/if}
{#for i in totalPages}
<a href="?page={i}" class="{#if i == page}active{/if}">
{i}
</a>
{/for}
{#if page < totalPages}
<a href="?page={page + 1}">Next</a>
{/if}
</nav>
{/let}Key Java APIs for working with Qute templates:
// Engine creation
Engine engine = Engine.builder()
.addDefaults()
.build();
// Parse template
Template template = engine.parse("Hello {name}!");
// Create instance with data
TemplateInstance instance = template
.data("name", "World")
.data("count", 42);
// Render synchronously
String output = instance.render();
// Render asynchronously
CompletionStage<String> future = instance.renderAsync();
// Get fragment
Fragment fragment = template.getFragment("fragmentId");
// Type-safe templates (Quarkus)
@CheckedTemplate
public class Templates {
public static native TemplateInstance hello(String name);
}
// Template extension (Quarkus)
@TemplateExtension
public class MyExtensions {
public static String upper(String str) {
return str.toUpperCase();
}
}
// Template global (Quarkus)
@TemplateGlobal
public class Globals {
public static final String APP_NAME = "MyApp";
public static String formatDate(LocalDate date) {
return date.format(DateTimeFormatter.ISO_DATE);
}
}
// Namespace resolver
NamespaceResolver resolver = NamespaceResolver.builder("mydata")
.resolve(ctx -> dataService.getData(ctx.getName()))
.build();
// Value resolver
ValueResolver resolver = ValueResolver.builder()
.appliesTo(ctx -> ctx.getBase() instanceof MyClass)
.resolveSync(ctx -> ((MyClass) ctx.getBase()).getValue())
.build();This comprehensive reference covers all major features of Qute template syntax including edge cases and common pitfalls. For Quarkus-specific features like CDI integration, message bundles, and configuration access, refer to the related documentation files.