1. Preparations

include in pom.xml
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-resteasy-qute</artifactId>
</dependency>

2. Sources

3. Example 1: Hello World

├── java
│   └── at
│       └── htl
│           └── qute
│               └── HelloResource.java
└── resources
    ├── application.properties
    └── templates
        └── subdir
            └── hello.txt
hello.txt
Hello {name}!
HelloResource.java
@Path("/hello")
public class HelloResource {

    @Location("subdir/hello.txt")
    Template hello;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return hello.data("name", name);
    }
}
qute 01 browser hello

4. Example 2: Type-Safe Templates

├── java
│   └── at
│       └── htl
│           └── qute
│               └── HelloResource.java
└── resources
    ├── application.properties
    └── templates
        └── HelloResource
            └── hello.txt
hello.txt
Hello {name} from HelloResource!
HelloResource.java
@Path("hello")
public class HelloResource {

    @CheckedTemplate
    public static class Templates {
        public static native TemplateInstance hello(String name);
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return Templates.hello(name);
    }
}

5. Example 3: Top-Level Type-Safe Templates

  • The templates are located in the top-level template-folder.

├── java
│   └── at
│       └── htl
│           └── qute
│               ├── HelloResource.java
│               └── Templates.java
└── resources
    ├── application.properties
    └── templates
        └── hello.txt
hello.txt
Hello {name} from top-level!
HelloResource.java
@Path("hello")
public class HelloResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return Templates.hello(name);
    }
}
Templates
@CheckedTemplate
public class Templates {

    public static native TemplateInstance hello(String name);
}
qute 02 browser type safe template

6. Example 4: Template Parameter Declarations

├── java
│   └── at
│       └── htl
│           └── qute
│               ├── Item.java
│               ├── ItemResource.java
│               └── ItemService.java
└── resources
    ├── application.properties
    └── templates
        └── ItemResource
            └── item.html
item.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{item.name}</title>
</head>
<body>
    <h1>{item.name}</h1>
    <div>Price: {item.price}</div>
</body>
</html>
Item.java
public class Item {

    public BigDecimal price;
    public String name;

    public Item(BigDecimal price, String name) {
        this.price = price;
        this.name = name;
    }
}
ItemService.java
package at.htl.qute;

import javax.enterprise.context.ApplicationScoped;
import java.math.BigDecimal;

@ApplicationScoped
public class ItemService {

    public Item findItem(int id) {
        return new Item(new BigDecimal("10.20"), "Apfelkuchen");
    }

}
ItemResource.java
@Path("item")
public class ItemResource {

    @Inject
    ItemService service;

    @CheckedTemplate
    public static class Templates {
        public static native TemplateInstance item(Item item);
    }

    @GET
    @Path("{id}")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get(@PathParam("id") Integer id) {
        return Templates.item(service.findItem(id));
    }
}
qute 03 browser.type safe parameter

7. Example 5: Template parameter declaration inside the template itself

├── java
│   └── at
│       └── htl
│           └── qute
│               ├── Item.java
│               ├── ItemResource.java
│               └── ItemService.java
└── resources
    ├── application.properties
    └── templates
        └── ItemResource
            └── item.html
Item.java
public class Item {

    public BigDecimal price;
    public String name;

    public Item(BigDecimal price, String name) {
        this.price = price;
        this.name = name;
    }
}
ItemService.java
@ApplicationScoped
public class ItemService {

    public Item findItem(int id) {
        return new Item(new BigDecimal("10.20"), "Apfelkuchen");
    }

}
ItemResource.java
@Path("item")
public class ItemResource {

    @Inject
    ItemService service;

    @Inject
    @Location("ItemResource/item")
    Template item;

    @GET
    @Path("{id}")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get(@PathParam("id") Integer id) {
        return item.data("item", service.findItem(id));
    }
}
qute 03 browser.type safe parameter

8. Example 6: Template Extension Methods

  • Template extension methods are used to extend the set of accessible properties of data objects.

  • Sometimes, you’re not in control of the classes that you want to use in your template, and you cannot add methods to them. Template extension methods allow you to declare new methods for those classes that will be available from your templates just as if they belonged to the target class.

├── java
│   └── at
│       └── htl
│           └── qute
│               ├── Item.java
│               ├── ItemResource.java
│               ├── ItemService.java
│               └── TemplateExtensions.java
└── resources
    ├── application.properties
    └── templates
        └── ItemResource
            └── item.html
item.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{item.name}</title>
</head>
<body>
    <h1>{item.name}</h1>
    <div>Price: {item.price}</div>
    {#if item.price > 100}
        <div>Discounted Price: {item.discountedPrice}</div>
    {/if}
</body>
</html>
TemplateExtensions.java
@TemplateExtension
public class TemplateExtensions {

    public static BigDecimal discountedPrice(Item item) {
        return item.price.multiply(new BigDecimal("0.9"));
    }
}
qute 04 browser extensions 1
qute 05 browser extensions 2

9. Example 7: Rendering Periodic Reports

├── java
│ └── at
│     └── htl
│         └── qute
│             ├── ReportGenerator.java
│             ├── Sample.java
│             └── SampleService.java
└── resources
    ├── application.properties
    └── templates
        └── reports
          └── v1
              └── report_01.json.template
report_01.json.template
\{
    "time": "{now}",
    "samples": [
      {#for sample in samples}
      \{"name": "{sample.name ?: 'Unknown'}","data": "{#if sample.valid}{sample.data}{#else}--Invalid--{/if}"}{#if count < samples.size },{/if}
      {/for}
    ]
}
Sample.java
public class Sample {
    public boolean valid;
    public String name;
    public String data;

    public Sample(boolean valid, String name, String data) {
        this.valid = valid;
        this.name = name;
        this.data = data;
    }
}
SampleService.java
@ApplicationScoped
public class SampleService {

    private static final String[] names = {"James", "Deepak", "Daniel", "Shaaf", "Jeff", "Sally"};

    public List<Sample> get() {
        int count = new Random().nextInt(10);
        List<Sample> result = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            boolean valid = false;
            if (Math.random() > 0.5) {
                valid = true;
            }
            result.add(new Sample(valid, names[(int)(Math.random() * names.length)], Math.random() + ""));
        }
        return result;
    }
}
ReportGenerator.java
@ApplicationScoped
public class ReportGenerator {

    @Inject
    SampleService service;

    private FileWriter fout = null;

    @Location("reports/v1/report_01.json.template")
    Template report;

    @Scheduled(cron="* * * ? * *")
    void generate() throws Exception {
        String result = report
                .data("samples", service.get())
                .data("now", java.time.LocalDateTime.now())
                .render();
        System.out.println("report: " + result);
        if (fout != null) {
            fout.write(result + "\n");
            fout.flush();
        }

    }

    void onStart(@Observes StartupEvent ev) throws Exception {
        fout = new FileWriter("/tmp/report.json", true);
    }
    void onShutdown(@Observes ShutdownEvent ev) throws Exception {
        fout.close();
        fout = null;
    }
}

10. Further Sources