Qute behaves strangely when including template that calls method with parameters

381 views
Skip to first unread message

Ivan St. Ivanov

unread,
Mar 25, 2021, 11:26:46 AM3/25/21
to Quarkus Development mailing list
Hi folks,

I noticed a pretty weird behavior of the Qute template engine when used with Quarkus JAX-RS. It's a bit longish to explain, but I have a reproducer in github as well (https://github.com/ivannov/qute-include).

So, this is a very simple project with a couple of templates, an endpoint and one POJO that is not a CDI bean. To start with, here's the POJO:
public class TemplateContext {

public String printData(String data) {
return data;
}

}
The endpoint creates an instance of this POJO and passes it as a parameter to the template instance that is returned:
@Path("/")
public class QuteResource {

@CheckedTemplate
public static class Templates {
public static native TemplateInstance test(TemplateContext context);
}

@GET
@Produces(MediaType.TEXT_HTML)
public TemplateInstance get() {
return Templates.test(new TemplateContext());
}

}
If the template itself uses directly the POJO, it works fine:
<body>
Hello from test template
<p>
Context data: {context.printData("Hello")}
</body>
This will yield as expected:

Hello from test template

Context data: Hello

But, if I extract the Context data: .... line in a template and include that new temple in the above one:

include.html:
Context data: {context.printData("Hello")}
test.html:
<body>
Hello from test template
<p>
{#include include /}
</body>
This would yield:

Hello from test template

Context data: NOT_FOUND

So, when I moved calling the POJO method into an included template, the method is not resolved anymore.

Why I think it's weird is that if the method doesn't take parameters, it works fine even when the template is included.

Moreover, if I call the method both in the base and in the included templates, it works fine too:
<body>
Hello from test template
<p>
Context data: {context.printData("Hello from base")}
<p>
{#include include /}
</body>
 Yields:

Hello from test template

Context data: Hello from base

Context data: Hello

So, am I doing something wrong? Maybe there are better ways to pass such POJOs with helpful utility functions between templates? But still, this behavior is quite strange: when the base template calls the method it can be resolved in the included one, otherwise - not.

Thanks,
Ivan



Martin Kouba

unread,
Mar 26, 2021, 3:36:11 AM3/26/21
to ivan.st...@gmail.com, Quarkus Development mailing list
Hi Ivan,

I'll take a look at the reproducer later today. The behavior you
describe is really weird.

Martin

On 25. 03. 21 16:26, Ivan St. Ivanov wrote:
> Hi folks,
>
> I noticed a pretty weird behavior of the Qute template engine when used
> with Quarkus JAX-RS. It's a bit longish to explain, but I have a
> reproducer in github as well (https://github.com/ivannov/qute-include
> <https://github.com/ivannov/qute-include>).
> But, if I extract the /Context data: ..../ line in a template and
> --
> You received this message because you are subscribed to the Google
> Groups "Quarkus Development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to quarkus-dev...@googlegroups.com
> <mailto:quarkus-dev...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/quarkus-dev/CACYLA9FSDxYXJECORpDgfeymUc%2B5PnwBBMibHDuvE7%3Ds_MmZ4Q%40mail.gmail.com
> <https://groups.google.com/d/msgid/quarkus-dev/CACYLA9FSDxYXJECORpDgfeymUc%2B5PnwBBMibHDuvE7%3Ds_MmZ4Q%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
Martin Kouba
Software Engineer
Red Hat, Czech Republic

Martin Kouba

unread,
Mar 29, 2021, 4:47:45 AM3/29/21
to ivan.st...@gmail.com, Quarkus Development mailing list
I think that I found the problem.

TLDR
====

The generated value resolver does not cover the expression used in the
included template. Workarounds exists: (1) Add the param declaration [1]
to the "include" template: {@org.acme.TemplateContext context}, or (2)
Annotate the TemplateContext with @io.quarkus.qute.TemplateData:

@TemplateData
public class TemplateContext {...}

Full story
==========

When a value resolver is generated for a class used as a param of a
method in a @CheckedTemplate, the resolver is optimized to only contain
the members used in templates (so that if there is class with 100
getters but only 1 is used in a template, then the generated resolver
only knows how to resolve the specific getter).

Unfortunately, we can't detect the usage in an included template.
Similarly, we don't validate the expressions in included templates
(unless it has a template param declaration). The reason is that the
included template could be used from different templates.

Workarounds:
(1) Param declaration adds printData() to the set of used members,
(2) An explicit @io.quarkus.qute.TemplateData overrides the optimized
behavior and ignores no members by default.

HTH
Martin

[1]
https://quarkus.io/guides/qute-reference#typesafe_expressions

Ivan St. Ivanov

unread,
Mar 31, 2021, 3:34:29 PM3/31/21
to Martin Kouba, Quarkus Development mailing list
Thanks a lot Martin!

Both of your suggestions work!
Reply all
Reply to author
Forward
0 new messages