Skip to content

Commit d85129e

Browse files
committed
Qute: fix template global class generation in the dev mode #2
- follows-up on quarkusio#45771 - fixes quarkusio#46005
1 parent 1597a94 commit d85129e

File tree

3 files changed

+35
-13
lines changed

3 files changed

+35
-13
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public boolean test(String t) {
5353
return false;
5454
}
5555
});
56-
try (ClassCreator classCreator = ClassCreator.builder().className("io.quarkus.qute.test.QuteDummyGlobals")
56+
try (ClassCreator classCreator = ClassCreator.builder().className("org.acme.qute.test.QuteDummyGlobals")
5757
.classOutput(gizmoAdaptor).build()) {
5858
classCreator.addAnnotation(TemplateGlobal.class);
5959

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

+22-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.HashMap;
2525
import java.util.HashSet;
2626
import java.util.Iterator;
27+
import java.util.LinkedHashMap;
2728
import java.util.List;
2829
import java.util.ListIterator;
2930
import java.util.Map;
@@ -2095,16 +2096,26 @@ public Function<FieldInfo, String> apply(ClassInfo clazz) {
20952096

20962097
if (!templateGlobals.isEmpty()) {
20972098
Set<String> generatedGlobals = new HashSet<>();
2098-
// The initial priority is increased during live reload so that priorities of non-application globals
2099-
// do not conflict with priorities of application globals
2100-
int initialPriority = -1000 + existingValueResolvers.globals.size();
2099+
// The classes for non-application globals are only generated during the first run because they can't be reloaded
2100+
// by the class loader during hot reload
2101+
// However, we need to make sure the priorities used by non-application globals do not conflict
2102+
// with priorities of application globals that are regenerated during each hot reload
2103+
// Therefore, the initial priority is increased by the number of all globals ever found
2104+
// For example, if there are three globals [A, B, C] (A and C are non-application classes)
2105+
// The intial priority during the first hot reload will be "-1000 + 3 = 997"
2106+
// If a global D is added afterwards, the initial priority during the subsequent hot reload will be "-1000 + 4 = 996"
2107+
// If the global D is removed, the initial priority will still remain "-1000 + 4 = 996"
2108+
// This way we can be sure that the priorities assigned to A and C will never conflict with priorities of B and D or any other application global class
2109+
int initialPriority = -1000 + existingValueResolvers.allGlobals.size();
21012110

21022111
TemplateGlobalGenerator globalGenerator = new TemplateGlobalGenerator(classOutput, GLOBAL_NAMESPACE,
21032112
initialPriority, index);
21042113

2105-
Map<DotName, Map<String, AnnotationTarget>> classToTargets = new HashMap<>();
2114+
Map<DotName, Map<String, AnnotationTarget>> classToTargets = new LinkedHashMap<>();
21062115
Map<DotName, List<TemplateGlobalBuildItem>> classToGlobals = templateGlobals.stream()
2107-
.collect(Collectors.groupingBy(TemplateGlobalBuildItem::getDeclaringClass));
2116+
.sorted(Comparator.comparing(g -> g.getDeclaringClass()))
2117+
.collect(Collectors.groupingBy(TemplateGlobalBuildItem::getDeclaringClass, LinkedHashMap::new,
2118+
Collectors.toList()));
21082119
for (Entry<DotName, List<TemplateGlobalBuildItem>> entry : classToGlobals.entrySet()) {
21092120
classToTargets.put(entry.getKey(), entry.getValue().stream().collect(
21102121
Collectors.toMap(TemplateGlobalBuildItem::getName, TemplateGlobalBuildItem::getTarget)));
@@ -2116,8 +2127,8 @@ public Function<FieldInfo, String> apply(ClassInfo clazz) {
21162127
generatedGlobals.add(generatedClass);
21172128
} else {
21182129
generatedClass = globalGenerator.generate(index.getClassByName(e.getKey()), e.getValue());
2119-
existingValueResolvers.addGlobal(e.getKey(), generatedClass, applicationClassPredicate);
21202130
}
2131+
existingValueResolvers.addGlobal(e.getKey(), generatedClass, applicationClassPredicate);
21212132
}
21222133
generatedGlobals.addAll(globalGenerator.getGeneratedTypes());
21232134

@@ -2135,9 +2146,12 @@ public Function<FieldInfo, String> apply(ClassInfo clazz) {
21352146
static class ExistingValueResolvers {
21362147

21372148
final Map<String, String> identifiersToGeneratedClass = new HashMap<>();
2138-
// class declaring globals -> generated type
2149+
2150+
// class declaring globals -> generated type; non-application globals only
21392151
final Map<String, String> globals = new HashMap<>();
21402152

2153+
final Set<String> allGlobals = new HashSet<>();
2154+
21412155
boolean contains(MethodInfo extensionMethod) {
21422156
return identifiersToGeneratedClass
21432157
.containsKey(toKey(extensionMethod));
@@ -2158,7 +2172,7 @@ void add(MethodInfo extensionMethod, String className, Predicate<DotName> applic
21582172
}
21592173

21602174
void addGlobal(DotName declaringClassName, String generatedClassName, Predicate<DotName> applicationClassPredicate) {
2161-
if (!applicationClassPredicate.test(declaringClassName)) {
2175+
if (allGlobals.add(generatedClassName.toString()) && !applicationClassPredicate.test(declaringClassName)) {
21622176
globals.put(declaringClassName.toString(), generatedClassName);
21632177
}
21642178
}

extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/devmode/TemplateGlobalDevModeTest.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.junit.jupiter.api.Test;
88
import org.junit.jupiter.api.extension.RegisterExtension;
99

10+
import io.quarkus.qute.TemplateGlobal;
1011
import io.quarkus.test.QuarkusDevModeTest;
1112

1213
/**
@@ -20,17 +21,17 @@ public class TemplateGlobalDevModeTest {
2021
@RegisterExtension
2122
static final QuarkusDevModeTest config = new QuarkusDevModeTest()
2223
.withApplicationRoot(root -> root
23-
.addClasses(TestRoute.class, QuteDummyTemplateGlobalMarker.class)
24+
.addClasses(TestRoute.class, MyGlobals.class, QuteDummyTemplateGlobalMarker.class)
2425
.addAsResource(new StringAsset(
25-
"{quteDummyFoo}:{testFoo ?: 'NA'}"),
26+
"{foo}:{quteDummyFoo}:{testFoo ?: 'NA'}"),
2627
"templates/test.html"));
2728

2829
@Test
2930
public void testTemplateGlobals() {
3031
given().get("test")
3132
.then()
3233
.statusCode(200)
33-
.body(Matchers.equalTo("bar:NA"));
34+
.body(Matchers.equalTo("24:bar:NA"));
3435

3536
// Add application globals - the priority sequence should be automatically
3637
// increased before it's used for TestGlobals
@@ -39,7 +40,14 @@ public void testTemplateGlobals() {
3940
given().get("test")
4041
.then()
4142
.statusCode(200)
42-
.body(Matchers.equalTo("bar:baz"));
43+
.body(Matchers.equalTo("24:bar:baz"));
44+
}
45+
46+
@TemplateGlobal
47+
public static class MyGlobals {
48+
49+
public static int foo = 24;
50+
4351
}
4452

4553
}

0 commit comments

Comments
 (0)