diff --git a/docs/src/main/asciidoc/qute-reference.adoc b/docs/src/main/asciidoc/qute-reference.adoc index 3ea30448d2e27..1a2fd29c39dfa 100644 --- a/docs/src/main/asciidoc/qute-reference.adoc +++ b/docs/src/main/asciidoc/qute-reference.adoc @@ -1613,7 +1613,7 @@ TIP: A map value can be also accessed directly: `{map.myKey}`. Use the bracket n * `takeLast`: Returns the last `n` elements from the given list; throws an `IndexOutOfBoundsException` if `n` is out of range ** `{#for r in recordsList.takeLast(3)}` -TIP: A list element can be accessed directly: `{list.10}` or `{list[10]}`. +TIP: A list element can be accessed directly via an index: `{list.10}` or even `{list[10]}`. ===== Numbers diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolvers.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolvers.java index 95b3ca3d7f0b3..c7477a1bef117 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolvers.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolvers.java @@ -41,6 +41,12 @@ public CompletionStage resolve(EvalContext context) { public static ValueResolver listResolver() { return new ValueResolver() { + @Override + public int getPriority() { + // Use this resolver before collectionResolver() + return WithPriority.DEFAULT_PRIORITY + 1; + } + public boolean appliesTo(EvalContext context) { return ValueResolver.matchClass(context, List.class); } @@ -397,7 +403,8 @@ private static CompletionStage collectionResolveAsync(EvalContext contex private static CompletionStage listResolveAsync(EvalContext context) { List list = (List) context.getBase(); - switch (context.getName()) { + String name = context.getName(); + switch (name) { case "get": if (context.getParams().size() == 1) { return context.evaluate(context.getParams().get(0)) @@ -445,7 +452,14 @@ private static CompletionStage listResolveAsync(EvalContext context) { }); } default: - return Results.notFound(context); + // Try to use the name as an index + int index; + try { + index = Integer.parseInt(name); + } catch (NumberFormatException e) { + return Results.notFound(context); + } + return CompletedStage.of(list.get(index)); } } diff --git a/independent-projects/qute/core/src/test/java/io/quarkus/qute/ListResolverTest.java b/independent-projects/qute/core/src/test/java/io/quarkus/qute/ListResolverTest.java new file mode 100644 index 0000000000000..cf4ea75a7494c --- /dev/null +++ b/independent-projects/qute/core/src/test/java/io/quarkus/qute/ListResolverTest.java @@ -0,0 +1,25 @@ +package io.quarkus.qute; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class ListResolverTest { + + @Test + public void tesResolver() { + List list = List.of("jedna", "dva", "tri"); + Engine engine = Engine.builder().addDefaults().build(); + assertEquals("3::jedna::jedna::dva::tri", + engine.parse("{list.size}::{list.get(0)}::{list.take(1).0}::{list.takeLast(2).get(0)}::{list.2}") + .data("list", list).render()); + assertThatExceptionOfType(TemplateException.class) + .isThrownBy(() -> engine.parse("{list.abc}").data("list", List.of()).render()) + .withMessageContaining( + "Property \"abc\" not found on the base object") + .withMessageContaining("in expression {list.abc}"); + } + +}