diff --git a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java index 3173fa08980fc..63dedf65e0677 100644 --- a/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java +++ b/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java @@ -642,26 +642,28 @@ static Match validateNestedExpressions(TemplateAnalysis templateAnalysis, ClassI } } } - if (member == null) { - // Then try to find an etension method - member = findTemplateExtensionMethod(info, match.type(), templateExtensionMethods, expression, - index, - templateIdToPathFun, results); - } - if (member == null) { - // Test whether the validation should be skipped - TypeCheck check = new TypeCheck( - info.isProperty() ? info.asProperty().name : info.asVirtualMethod().name, - match.clazz(), - info.part.isVirtualMethod() ? info.part.asVirtualMethod().getParameters().size() : -1); - if (isExcluded(check, excludes)) { - LOGGER.debugf( - "Expression part [%s] excluded from validation of [%s] against type [%s]", - info.value, - expression.toOriginalString(), match.type()); - match.clearValues(); - break; - } + } + + if (member == null) { + // Then try to find an etension method + member = findTemplateExtensionMethod(info, match.type(), templateExtensionMethods, expression, + index, + templateIdToPathFun, results); + } + + if (member == null) { + // Test whether the validation should be skipped + TypeCheck check = new TypeCheck( + info.isProperty() ? info.asProperty().name : info.asVirtualMethod().name, + match.clazz(), + info.part.isVirtualMethod() ? info.part.asVirtualMethod().getParameters().size() : -1); + if (isExcluded(check, excludes)) { + LOGGER.debugf( + "Expression part [%s] excluded from validation of [%s] against type [%s]", + info.value, + expression.toOriginalString(), match.type()); + match.clearValues(); + break; } } diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/Movie.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/Movie.java index 2254ca10cb0e5..540081bb4367b 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/Movie.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/Movie.java @@ -7,6 +7,8 @@ public class Movie { public final Boolean alwaysTrue; + public final boolean alwaysFalsePrimitive = false; + public final List mainCharacters; public Movie(String... mainCharacters) { diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/MovieExtensions.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/MovieExtensions.java index 024060acb449c..25b4361f5d82f 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/MovieExtensions.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/MovieExtensions.java @@ -17,4 +17,8 @@ static Long toLong(Movie movie, long... values) { return ret; } + static boolean negate(boolean val) { + return !val; + } + } diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/ValidationSuccessTest.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/ValidationSuccessTest.java index 971e140a808cf..c1cfa4ee322a4 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/ValidationSuccessTest.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/typesafe/ValidationSuccessTest.java @@ -30,6 +30,8 @@ public class ValidationSuccessTest { // Built-in value resolvers + "{movie.name ?: 'Mono'} " + "{movie.alwaysTrue ? 'Mono' : 'Stereo'} " + + "{movie.alwaysFalsePrimitive ? 'Mono' : 'Stereo'} " + + "{movie.alwaysFalsePrimitive.negate} " + "{movie.mainCharacters.size} " // Name and number of params ok and param type ignored + "{movie.findService('foo')} " @@ -53,7 +55,7 @@ public class ValidationSuccessTest { @Test public void testResult() { // Validation succeeded! Yay! - assertEquals("Jason Jason Mono 1 10 11 ok 43 3 ohn bar", + assertEquals("Jason Jason Mono Stereo true 1 10 11 ok 43 3 ohn bar", movie.data("movie", new Movie("John"), "name", "Vasik", "surname", "Hu", "age", 10l, "map", Collections.singletonMap("foo", "bar")).render()); } diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/DotNames.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/DotNames.java new file mode 100644 index 0000000000000..61df03a094cf0 --- /dev/null +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/DotNames.java @@ -0,0 +1,20 @@ +package io.quarkus.qute.generator; + +import java.util.concurrent.CompletionStage; +import org.jboss.jandex.DotName; + +final class DotNames { + + static final DotName BOOLEAN = DotName.createSimple(Boolean.class.getName()); + static final DotName BYTE = DotName.createSimple(Byte.class.getName()); + static final DotName CHARACTER = DotName.createSimple(Character.class.getName()); + static final DotName DOUBLE = DotName.createSimple(Double.class.getName()); + static final DotName FLOAT = DotName.createSimple(Float.class.getName()); + static final DotName INTEGER = DotName.createSimple(Integer.class.getName()); + static final DotName LONG = DotName.createSimple(Long.class.getName()); + static final DotName SHORT = DotName.createSimple(Short.class.getName()); + static final DotName STRING = DotName.createSimple(String.class.getName()); + static final DotName COMPLETION_STAGE = DotName.createSimple(CompletionStage.class.getName()); + static final DotName OBJECT = DotName.createSimple(Object.class.getName()); + +} diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java index 778152287c974..a5003037454b8 100644 --- a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java @@ -43,6 +43,7 @@ import org.jboss.jandex.DotName; import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.PrimitiveType.Primitive; import org.jboss.jandex.Type; import org.jboss.jandex.Type.Kind; @@ -55,8 +56,6 @@ public class ExtensionMethodGenerator { public static final DotName TEMPLATE_EXTENSION = DotName.createSimple(TemplateExtension.class.getName()); - static final DotName STRING = DotName.createSimple(String.class.getName()); - public static final String SUFFIX = "_Extension" + ValueResolverGenerator.SUFFIX; public static final String NAMESPACE_SUFFIX = "_Namespace" + SUFFIX; @@ -132,7 +131,7 @@ public void generate(MethodInfo method, String matchName, String matchRegex, Int if (matchRegex != null || matchName.equals(TemplateExtension.ANY)) { // The second parameter must be a string - if (parameters.size() < 2 || !parameters.get(1).name().equals(STRING)) { + if (parameters.size() < 2 || !parameters.get(1).name().equals(io.quarkus.qute.generator.DotNames.STRING)) { throw new TemplateException( "A template extension method matching multiple names or a regular expression must declare at least two parameters and the second parameter must be string: " + method); @@ -352,7 +351,8 @@ private void implementAppliesTo(ClassCreator valueResolver, MethodInfo method, S // Test base object class ResultHandle baseClass = appliesTo.invokeVirtualMethod(Descriptors.GET_CLASS, base); - ResultHandle testClass = appliesTo.loadClass(parameters.get(0).name().toString()); + // Perform autoboxing for primitives + ResultHandle testClass = appliesTo.loadClass(box(parameters.get(0)).name().toString()); ResultHandle baseClassTest = appliesTo.invokeVirtualMethod(Descriptors.IS_ASSIGNABLE_FROM, testClass, baseClass); BytecodeCreator baseNotAssignable = appliesTo.ifTrue(baseClassTest).falseBranch(); @@ -633,4 +633,34 @@ static String sha1(String value) { } } + static Type box(Type type) { + if (type.kind() == Kind.PRIMITIVE) { + return box(type.asPrimitiveType().primitive()); + } + return type; + } + + static Type box(Primitive primitive) { + switch (primitive) { + case BOOLEAN: + return Type.create(DotNames.BOOLEAN, Kind.CLASS); + case DOUBLE: + return Type.create(DotNames.DOUBLE, Kind.CLASS); + case FLOAT: + return Type.create(DotNames.FLOAT, Kind.CLASS); + case LONG: + return Type.create(DotNames.LONG, Kind.CLASS); + case INT: + return Type.create(DotNames.INTEGER, Kind.CLASS); + case BYTE: + return Type.create(DotNames.BYTE, Kind.CLASS); + case CHAR: + return Type.create(DotNames.CHARACTER, Kind.CLASS); + case SHORT: + return Type.create(DotNames.SHORT, Kind.CLASS); + default: + throw new IllegalArgumentException("Unsupported primitive: " + primitive); + } + } + } diff --git a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java index 4359e014736f0..53d281ea516b8 100644 --- a/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java +++ b/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ValueResolverGenerator.java @@ -64,10 +64,6 @@ public static Builder builder() { public static final DotName TEMPLATE_DATA = DotName.createSimple(TemplateData.class.getName()); public static final DotName TEMPLATE_DATA_CONTAINER = DotName.createSimple(TemplateData.Container.class.getName()); - private static final DotName COMPLETION_STAGE = DotName.createSimple(CompletionStage.class.getName()); - private static final DotName OBJECT = DotName.createSimple(Object.class.getName()); - private static final DotName BOOLEAN = DotName.createSimple(Boolean.class.getName()); - public static final String SUFFIX = "_ValueResolver"; public static final String NESTED_SEPARATOR = "$_"; @@ -115,7 +111,7 @@ public void generate() { Map> superToSub = new HashMap<>(); for (Entry entry : nameToClass.entrySet()) { DotName superName = entry.getValue().superName(); - if (superName != null && !OBJECT.equals(superName)) { + if (superName != null && !DotNames.OBJECT.equals(superName)) { superToSub.computeIfAbsent(superName, name -> new HashSet<>()).add(entry.getKey()); } } @@ -135,7 +131,7 @@ public void generate() { generate(entry.getKey(), priority); // Queue a class removal DotName superName = entry.getValue().superName(); - if (superName != null && !OBJECT.equals(superName)) { + if (superName != null && !DotNames.OBJECT.equals(superName)) { superToSubRemovals.computeIfAbsent(superName, name -> new HashSet<>()).add(entry.getKey()); } // Remove the processed binding @@ -229,7 +225,7 @@ private void implementResolve(ClassCreator valueResolver, String clazzName, Clas .collect(Collectors.toList()); if (!ignoreSuperclasses) { DotName superName = clazz.superName(); - while (superName != null && !superName.equals(OBJECT)) { + while (superName != null && !superName.equals(DotNames.OBJECT)) { ClassInfo superClass = index.getClassByName(superName); if (superClass != null) { methods.addAll( @@ -250,7 +246,7 @@ private void implementResolve(ClassCreator valueResolver, String clazzName, Clas if ((field.type().kind() == org.jboss.jandex.Type.Kind.PRIMITIVE && field.type().asPrimitiveType().equals(PrimitiveType.BOOLEAN)) || (field.type().kind() == org.jboss.jandex.Type.Kind.CLASS - && field.type().name().equals(BOOLEAN))) { + && field.type().name().equals(DotNames.BOOLEAN))) { getterName = IS_PREFIX + capitalize(field.name()); } else { getterName = GET_PREFIX + capitalize(field.name()); @@ -837,7 +833,7 @@ static boolean isGetterName(String name, Type returnType) { return true; } if (returnType == null - || (returnType.name().equals(PrimitiveType.BOOLEAN.name()) || returnType.name().equals(BOOLEAN))) { + || (returnType.name().equals(PrimitiveType.BOOLEAN.name()) || returnType.name().equals(DotNames.BOOLEAN))) { return name.startsWith(IS_PREFIX) || name.startsWith(HAS_PREFIX); } return false; @@ -939,7 +935,7 @@ static String generatedNameFromTarget(String targetPackage, String baseName, Str public static boolean hasCompletionStageInTypeClosure(ClassInfo classInfo, IndexView index) { - return hasClassInTypeClosure(classInfo, COMPLETION_STAGE, index); + return hasClassInTypeClosure(classInfo, DotNames.COMPLETION_STAGE, index); } public static boolean hasClassInTypeClosure(ClassInfo classInfo, DotName className,