Skip to content

Commit 1431243

Browse files
mkoubagastaldi
andcommitted
Qute generator: fix multiple namespace extension methods
- fixes quarkusio#50618 Co-authored-by: George Gastaldi <[email protected]>
1 parent bc6e670 commit 1431243

File tree

6 files changed

+516
-169
lines changed

6 files changed

+516
-169
lines changed

extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145
import io.quarkus.qute.deployment.TypeInfos.TypeInfo;
146146
import io.quarkus.qute.deployment.Types.AssignabilityCheck;
147147
import io.quarkus.qute.generator.ExtensionMethodGenerator;
148-
import io.quarkus.qute.generator.ExtensionMethodGenerator.ExtensionMethodInfo;
148+
import io.quarkus.qute.generator.ExtensionMethodGenerator.NamespaceExtensionMethodInfo;
149149
import io.quarkus.qute.generator.ExtensionMethodGenerator.Param;
150150
import io.quarkus.qute.generator.TemplateGlobalGenerator;
151151
import io.quarkus.qute.generator.ValueResolverGenerator;
@@ -2107,12 +2107,13 @@ public Function<FieldInfo, String> apply(ClassInfo clazz) {
21072107
.collect(Collectors.groupingBy(TemplateExtensionMethodBuildItem::getPriority));
21082108

21092109
for (Entry<Integer, List<TemplateExtensionMethodBuildItem>> priorityEntry : priorityToMethods.entrySet()) {
2110-
List<ExtensionMethodGenerator.ExtensionMethodInfo> extensionMethods = new ArrayList<>(
2110+
List<ExtensionMethodGenerator.NamespaceExtensionMethodInfo> extensionMethods = new ArrayList<>(
21112111
priorityEntry.getValue().size());
21122112
for (TemplateExtensionMethodBuildItem method : priorityEntry.getValue()) {
21132113
extensionMethods
2114-
.add(new ExtensionMethodInfo(method.getMethod(), method.getMatchName(), method.getMatchNames(),
2115-
method.getMatchRegex()));
2114+
.add(new NamespaceExtensionMethodInfo(method.getMethod(), method.getMatchName(),
2115+
Set.copyOf(method.getMatchNames()),
2116+
method.getMatchRegex(), method.getParams()));
21162117
}
21172118
String generatedType = extensionMethodGenerator.generateNamespaceResolver(
21182119
priorityEntry.getValue().get(0).getMethod().declaringClass(), nsEntry.getKey(),

independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatedParams.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,18 @@ public Object getResult(int index) throws InterruptedException, ExecutionExcepti
141141
*/
142142
public boolean parameterTypesMatch(boolean varargs, Class<?>[] types) throws InterruptedException, ExecutionException {
143143
// Check the number of parameters and replace the last param type with component type if needed
144+
Class<?> componentType = null;
144145
if (types.length == results.length) {
145146
if (varargs) {
146-
types[types.length - 1] = types[types.length - 1].getComponentType();
147+
componentType = boxType(types[types.length - 1].getComponentType());
147148
}
148149
} else {
149150
if (varargs) {
150151
int diff = types.length - results.length;
151152
if (diff > 1) {
152153
return false;
153154
} else if (diff < 1) {
154-
Class<?> varargsType = types[types.length - 1];
155-
types[types.length - 1] = varargsType.getComponentType();
155+
componentType = boxType(types[types.length - 1].getComponentType());
156156
}
157157
// if diff == 1 then vargs may be empty and we need to compare the result types
158158
} else {
@@ -165,7 +165,11 @@ public boolean parameterTypesMatch(boolean varargs, Class<?>[] types) throws Int
165165
Object result = getResult(i);
166166
if (result != null) {
167167
Class<?> resultClass = boxType(result.getClass());
168-
if (!paramType.isAssignableFrom(resultClass)) {
168+
if (!paramType.isAssignableFrom(resultClass)
169+
// For varargs we also try to match the component type
170+
&& (componentType == null
171+
|| i < (types.length - 1)
172+
|| !componentType.isAssignableFrom(resultClass))) {
169173
return false;
170174
}
171175
}
@@ -178,14 +182,30 @@ public boolean parameterTypesMatch(boolean varargs, Class<?>[] types) throws Int
178182

179183
public Object getVarargsResults(int numberOfParameters, Class<?> componentType)
180184
throws InterruptedException, ExecutionException {
185+
// For varargs we want to skip all previous args
181186
int skip = numberOfParameters - 1;
182-
if (skip < 0) {
187+
if (skip < 0 || skip >= results.length) {
183188
return Array.newInstance(componentType, 0);
184189
}
190+
Object result = null;
191+
int capacity = results.length - skip;
192+
if (numberOfParameters == results.length) {
193+
// If there is exactly one non-skipped argument
194+
// test if it's not a matching array
195+
result = getResult(skip);
196+
Class<?> resultClass = result.getClass();
197+
if (resultClass.isArray() && resultClass.getComponentType().equals(componentType)) {
198+
return result;
199+
}
200+
skip++;
201+
}
202+
Object array = Array.newInstance(componentType, capacity);
185203
int idx = 0;
186-
Object array = Array.newInstance(componentType, results.length - skip);
204+
if (result != null) {
205+
Array.set(array, idx++, result);
206+
}
187207
for (int i = skip; i < results.length; i++) {
188-
Object result = getResult(i);
208+
result = getResult(i);
189209
Array.set(array, idx++, result);
190210
}
191211
return array;

independent-projects/qute/core/src/main/java/io/quarkus/qute/TemplateExtension.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,13 @@
138138
int priority() default DEFAULT_PRIORITY;
139139

140140
/**
141-
* If not empty a namespace resolver is generated instead.
141+
* If not empty then a namespace resolver is generated.
142142
* <p>
143-
* Template extension methods that share the same namespace and are declared on the same class are grouped in one resolver
144-
* and ordered by {@link #priority()}. The first matching extension method is used to resolve an expression. Template
145-
* extension methods declared on different classes cannot share the same namespace.
143+
* Multiple extension methods declared on the same class can share the same namespace. However, extension methods declared
144+
* on different classes cannot share the same namespace.
145+
* <p>
146+
* It's recommended to specify the {@link #priority()} if multiple extension methods that share the same namespace also
147+
* match the same property/method name and parameters.
146148
*
147149
* @return the namespace
148150
* @see NamespaceResolver#getNamespace()

0 commit comments

Comments
 (0)