and Spring WebFlux (Johnson et al., 2004), being the
latter the most widely used Web framework in Java
according to several surveys, such as JetBrains’ State
of Java report (2021) and community activity, such as
Github and Stackoverflow.
Migrating legacy Web applications to state-of-the-
art low-thread Web servers, not only involves port-
ing the Web handlers (e.g. controllers (Alur et al.,
2001)), and data repositories (Fowler, 2002), but may
also concern the Frontend, when it uses a Server-
Side Rendering (SSR) approach (Alur et al., 2001),
where the Web server is also responsible for gener-
ating the HTML for a Web page. Although, Single-
Page Applications (SPAs) with Client-Side Rendering
(CSR) (Klauzinski and Moore, 2016) have become a
popular choice for building Frontend in modern Web
applications, Server-Side Rendering (SSR) still has a
significant installation base and continues to be used
in many Multi-Page applications.
However, only a few Java template engines prop-
erly deal with asynchronous data models. In our
work, we analyze a use-case of a Spring WebFlux ap-
plication and some limitations, and harmful effects,
that may emerge from the use of SSR Frontend with
asynchronous data models, such as: 1) unresponsive
blank page, 2) limited concurrency, 3) server runtime
exceptions, 4) ill-formed HTML, 5) single model use,
and 6) restricted asynchronous API.
Our work is built on top of HtmlFlow, a Java
DSL library for HTML. We present a new proposal
that addresses all the aforementioned issues through
the combination of three ideas: 1) functional tem-
plates, which regards the capacity of implementing
Web templates as higher-order functions (Carvalho.
and Duarte., 2019); 2) resume callback in continua-
tions (Haynes et al., 1984) to control transitions from
asynchronous handlers, and 3) chain-of-responsibility
design pattern (Gamma et al., 1995) to control the
flow between a chain of template fragments.
In the next section, we highlight some issues that
arise from the naive use of asynchronous techniques
in web templates. Then, in Section 3, we describe
state-of-the-art template engines for SSR. Following
that, in Section 4, we compare these template engines
in a case study of a Spring WebFlux application. Sec-
tion 5 explains how our proposal mitigates the lim-
itations of the competition. Next, in Section 6, we
evaluate different web templates and their issues re-
garding asynchronous data models. We conclude and
discuss future work in Section 7.
2 ASYNCHRONOUS APIs
MATTER
The non-blocking IO model used in low-thread
servers only functions properly if HTTP handlers do
not block. This implies that an HTTP handler can-
not wait for IO completion, such as reading a file,
querying a database, or any other kind of IO opera-
tion. Therefore, handlers must be designed to initiate
IO operations and return immediately, allowing other
handlers to execute while the IO operation completes
in the background. To ensure non-blocking I/O, han-
dlers should use asynchronous APIs to access data.
Asynchronous APIs allow handlers to submit requests
and receive notifications when operations complete,
all without blocking the thread.
However, while using a synchronous API can be
straightforward with its direct style of producing re-
sults through the returned value of function calls,
dealing with an asynchronous API can be more chal-
lenging. Asynchronous APIs do not have a stan-
dard approach, leading to several proposals such
as continuation-passing style (CPS) (Sussman and
Steele, 1975), async/await idiom (Syme et al., 2011),
reactive streams (Reactive Streams, 2015), Kotlin
Flow (Breslav, 2016), and others. The correct use
of an asynchronous API can help ensure that code
is efficient, reliable, and maintainable. On the other
hand, dealing with asynchronous data models in a
naive way, may produce several harmful effects. In
the context of a web server we may observe the fol-
lowing problems, not limited to:
1. unresponsive blank page;
2. limited concurrency,
3. server runtime exceptions.
A naive way of dealing with an asynchronous API
is blocking on completion. For example, in the Java
CompletableFuture, which is an implementation of
a Promise (Friedman and Wise, 1978), this may be
achieved getting its result from its method join():
T. This blocking approach can be used in any tem-
plate engine, including those analyzed in this work
(i.e. Thymeleaf, KotlinX.html and HtmlFlow) with
the same ill effect. These kind of handlers will pro-
duce an unresponsive blank page in the browser. Only
when all data models are completed we may see a re-
sulting HTML document. Rather than a progressive
behavior where the page would be rendered smoothly
as data becomes available, we will have an all or noth-
ing effect starting with a blank page and finishing with
the complete page.
Furthermore, while an handler is waiting for data
completion it is blocking a thread and preventing it
WEBIST 2023 - 19th International Conference on Web Information Systems and Technologies
38