Skip to content

Commit 081a1cc

Browse files
authored
Merge pull request quarkusio#53172 from gsmet/restore-builditem-comparable
Reintroduce the automated sort of Comparable MultiBuildItems
2 parents 8c80ca2 + 616ff11 commit 081a1cc

10 files changed

Lines changed: 114 additions & 37 deletions

File tree

core/builder/src/main/java/io/quarkus/builder/ItemId.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,22 @@
88

99
final class ItemId {
1010
private final Class<? extends BuildItem> itemType;
11+
private final boolean comparable;
1112

1213
ItemId(final Class<? extends BuildItem> itemType) {
1314
Assert.checkNotNullParam("itemType", itemType);
1415
this.itemType = itemType;
16+
this.comparable = Comparable.class.isAssignableFrom(itemType);
1517
}
1618

1719
boolean isMulti() {
1820
return MultiBuildItem.class.isAssignableFrom(itemType);
1921
}
2022

23+
boolean isComparable() {
24+
return comparable;
25+
}
26+
2127
@Override
2228
public boolean equals(Object obj) {
2329
return obj instanceof ItemId && equals((ItemId) obj);

core/builder/src/main/java/io/quarkus/builder/MultiBuildItems.java

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.ArrayList;
44
import java.util.Arrays;
5+
import java.util.Collections;
56
import java.util.HashMap;
67
import java.util.List;
78
import java.util.Map;
@@ -26,7 +27,11 @@ class MultiBuildItems {
2627
this.producingOrdinals = producingOrdinals;
2728
final Map<ItemId, List<MultiBuildItem>[]> ms = new HashMap<ItemId, List<MultiBuildItem>[]>(producingOrdinals.size());
2829
for (Entry<ItemId, int[]> en : producingOrdinals.entrySet()) {
29-
ms.put(en.getKey(), new List[en.getValue().length + 1]);
30+
if (en.getKey().isComparable()) {
31+
ms.put(en.getKey(), new List[1]);
32+
} else {
33+
ms.put(en.getKey(), new List[en.getValue().length + 1]);
34+
}
3035
}
3136
this.multis = ms;
3237
}
@@ -39,16 +44,30 @@ class MultiBuildItems {
3944
* @param id the {@link ItemId} to store the given {@code value} under
4045
* @param value the {@link MultiBuildItem} to store.
4146
*/
47+
@SuppressWarnings({ "unchecked", "rawtypes" })
4248
void put(int ordinal, ItemId id, MultiBuildItem value) {
4349
final List<MultiBuildItem>[] list = multis.get(id);
44-
int pos = Arrays.binarySearch(producingOrdinals.get(id), ordinal);
4550
synchronized (list) {
46-
List<MultiBuildItem> entry = list[pos + 1];
47-
if (entry == null) {
48-
entry = new ArrayList<MultiBuildItem>();
49-
list[pos + 1] = entry;
51+
if (id.isComparable()) {
52+
List<MultiBuildItem> entry = list[0];
53+
if (entry == null) {
54+
entry = new ArrayList<>();
55+
list[0] = entry;
56+
}
57+
int idx = Collections.binarySearch((List) entry, value);
58+
if (idx < 0) {
59+
idx = -idx - 1;
60+
}
61+
entry.add(idx, value);
62+
} else {
63+
int pos = Arrays.binarySearch(producingOrdinals.get(id), ordinal);
64+
List<MultiBuildItem> entry = list[pos + 1];
65+
if (entry == null) {
66+
entry = new ArrayList<>();
67+
list[pos + 1] = entry;
68+
}
69+
entry.add(value);
5070
}
51-
entry.add(value);
5271
}
5372
}
5473

@@ -59,16 +78,29 @@ void put(int ordinal, ItemId id, MultiBuildItem value) {
5978
* @param id the {@link ItemId} to store the given {@code value} under
6079
* @param value the {@link MultiBuildItem} to store.
6180
*/
81+
@SuppressWarnings({ "unchecked", "rawtypes" })
6282
void putInitial(ItemId id, MultiBuildItem value) {
63-
@SuppressWarnings("unchecked")
6483
final List<MultiBuildItem>[] list = multis.computeIfAbsent(id, x -> new ArrayList[1]);
6584
synchronized (list) {
66-
List<MultiBuildItem> entry = list[0];
67-
if (entry == null) {
68-
entry = new ArrayList<MultiBuildItem>();
69-
list[0] = entry;
85+
if (id.isComparable()) {
86+
List<MultiBuildItem> entry = list[0];
87+
if (entry == null) {
88+
entry = new ArrayList<>();
89+
list[0] = entry;
90+
}
91+
int idx = Collections.binarySearch((List) entry, value);
92+
if (idx < 0) {
93+
idx = -idx - 1;
94+
}
95+
entry.add(idx, value);
96+
} else {
97+
List<MultiBuildItem> entry = list[0];
98+
if (entry == null) {
99+
entry = new ArrayList<>();
100+
list[0] = entry;
101+
}
102+
entry.add(value);
70103
}
71-
entry.add(value);
72104
}
73105
}
74106

core/builder/src/main/java/io/quarkus/builder/item/MultiBuildItem.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package io.quarkus.builder.item;
22

33
/**
4-
* A build item that may be produced multiple times, and consumed as a {@code List}. {@code MultiBuildItem} subclasses
5-
* which implement {@code Comparable} will be returned in sorted order.
4+
* A build item that may be produced multiple times, and consumed as a {@code List}.
5+
* <p>
6+
* {@code MultiBuildItem} subclasses which implement {@code Comparable} will be returned in sorted order.
67
*/
78
public abstract class MultiBuildItem extends BuildItem {
89
protected MultiBuildItem() {

core/builder/src/test/java/io/quarkus/builder/MultiBuildItemsTest.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void testMultis() {
3838

3939
{
4040
final List<ComparableItem1> actual = multis.get(idC1);
41-
Assertions.assertEquals(Arrays.asList("c1.2", "c1.1"),
41+
Assertions.assertEquals(Arrays.asList("c1.1", "c1.2"),
4242
actual.stream().map(ComparableItem1::toString).collect(Collectors.toList()));
4343
}
4444

@@ -67,6 +67,29 @@ public void testMultis() {
6767

6868
}
6969

70+
@Test
71+
public void testComparableSorting() {
72+
final ItemId idC1 = new ItemId(ComparableItem1.class);
73+
74+
Map<ItemId, int[]> producingOrdinals = new HashMap<ItemId, int[]>();
75+
producingOrdinals.put(idC1, new int[] { 2, 4 });
76+
77+
final MultiBuildItems multis = new MultiBuildItems(producingOrdinals);
78+
79+
multis.putInitial(idC1, new ComparableItem1("c1.z"));
80+
multis.putInitial(idC1, new ComparableItem1("c1.a"));
81+
82+
multis.put(4, idC1, new ComparableItem1("c1.m"));
83+
multis.put(2, idC1, new ComparableItem1("c1.b"));
84+
multis.put(4, idC1, new ComparableItem1("c1.x"));
85+
multis.put(2, idC1, new ComparableItem1("c1.d"));
86+
87+
final List<ComparableItem1> actual = multis.get(idC1);
88+
Assertions.assertEquals(
89+
Arrays.asList("c1.a", "c1.b", "c1.d", "c1.m", "c1.x", "c1.z"),
90+
actual.stream().map(ComparableItem1::toString).collect(Collectors.toList()));
91+
}
92+
7093
public static final class Item1 extends MultiBuildItem {
7194
private final String name;
7295

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static io.quarkus.deployment.configuration.ConfigMappingUtils.CONFIG_MAPPING_NAME;
99
import static io.quarkus.deployment.configuration.ConfigMappingUtils.processConfigClasses;
1010
import static io.smallrye.config.ConfigMappings.ConfigClass.configClass;
11+
import static java.util.stream.Collectors.toCollection;
1112
import static java.util.stream.Collectors.toList;
1213
import static java.util.stream.Collectors.toSet;
1314
import static org.eclipse.microprofile.config.inject.ConfigProperties.UNCONFIGURED_PREFIX;
@@ -22,6 +23,7 @@
2223
import java.util.Collections;
2324
import java.util.HashMap;
2425
import java.util.HashSet;
26+
import java.util.LinkedHashSet;
2527
import java.util.List;
2628
import java.util.Map;
2729
import java.util.Set;
@@ -226,7 +228,7 @@ void validateStaticInitConfigProperty(
226228
configProperties.stream()
227229
.filter(ConfigPropertyBuildItem::isStaticInit)
228230
.map(p -> configPropertyToConfigValidation(p, reflectiveClass))
229-
.collect(toSet()));
231+
.collect(toCollection(LinkedHashSet::new)));
230232
}
231233

232234
@BuildStep
@@ -240,7 +242,7 @@ void validateRuntimeConfigProperty(
240242
configProperties.stream()
241243
.filter(ConfigPropertyBuildItem::isRuntimeInit)
242244
.map(p -> configPropertyToConfigValidation(p, reflectiveClass))
243-
.collect(toSet()));
245+
.collect(toCollection(LinkedHashSet::new)));
244246
}
245247

246248
@BuildStep

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/**
99
* Represents a mandatory config property that needs to be validated at runtime.
1010
*/
11-
public final class ConfigPropertyBuildItem extends MultiBuildItem {
11+
public final class ConfigPropertyBuildItem extends MultiBuildItem implements Comparable<ConfigPropertyBuildItem> {
1212
private final String propertyName;
1313
private final Type propertyType;
1414
private final String defaultValue;
@@ -50,6 +50,11 @@ public boolean isRuntimeInit() {
5050
return executionMode.equals(ExecutionMode.RUNTIME_INIT);
5151
}
5252

53+
@Override
54+
public int compareTo(ConfigPropertyBuildItem other) {
55+
return this.propertyName.compareTo(other.propertyName);
56+
}
57+
5358
public static ConfigPropertyBuildItem staticInit(
5459
final String propertyName,
5560
final Type propertyType,

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.quarkus.deployment.annotations.ExecutionTime;
1919
import io.quarkus.deployment.recording.BytecodeRecorderImpl.ReturnedProxy;
2020
import io.quarkus.runtime.RuntimeValue;
21+
import io.quarkus.runtime.util.HashUtil;
2122

2223
/**
2324
* Makes it possible to register a synthetic bean.
@@ -29,7 +30,7 @@
2930
* @see ExtendedBeanConfigurator
3031
* @see BeanRegistrar
3132
*/
32-
public final class SyntheticBeanBuildItem extends MultiBuildItem {
33+
public final class SyntheticBeanBuildItem extends MultiBuildItem implements Comparable<SyntheticBeanBuildItem> {
3334

3435
/**
3536
* Returns a configurator object allowing for further customization of the synthetic bean.
@@ -84,15 +85,28 @@ public static ExtendedBeanConfigurator create(DotName implClazz) {
8485
}
8586

8687
private final ExtendedBeanConfigurator configurator;
88+
private final String name;
8789

8890
SyntheticBeanBuildItem(ExtendedBeanConfigurator configurator) {
8991
this.configurator = configurator;
92+
this.name = configurator.getImplClazz().toString().replace(".", "_") + "_"
93+
+ HashUtil.sha1(configurator.getTypes().toString() + configurator.getQualifiers().toString()
94+
+ (configurator.getIdentifier() != null ? configurator.getIdentifier() : ""));
9095
}
9196

9297
ExtendedBeanConfigurator configurator() {
9398
return configurator;
9499
}
95100

101+
String name() {
102+
return name;
103+
}
104+
105+
@Override
106+
public int compareTo(SyntheticBeanBuildItem other) {
107+
return this.name.compareTo(other.name);
108+
}
109+
96110
boolean isStaticInit() {
97111
return configurator.staticInit;
98112
}

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeansProcessor.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.quarkus.arc.deployment;
22

3-
import java.util.HashMap;
3+
import java.util.LinkedHashMap;
44
import java.util.List;
55
import java.util.Map;
66
import java.util.function.Consumer;
@@ -12,7 +12,6 @@
1212
import io.quarkus.arc.ActiveResult;
1313
import io.quarkus.arc.SyntheticCreationalContext;
1414
import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem;
15-
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
1615
import io.quarkus.arc.processor.BeanConfigurator;
1716
import io.quarkus.arc.processor.BeanConfiguratorBase;
1817
import io.quarkus.arc.runtime.ArcRecorder;
@@ -29,7 +28,6 @@
2928
import io.quarkus.gizmo2.creator.BlockCreator;
3029
import io.quarkus.gizmo2.desc.FieldDesc;
3130
import io.quarkus.gizmo2.desc.MethodDesc;
32-
import io.quarkus.runtime.util.HashUtil;
3331

3432
public class SyntheticBeansProcessor {
3533

@@ -38,8 +36,8 @@ public class SyntheticBeansProcessor {
3836
void initStatic(ArcRecorder recorder, List<SyntheticBeanBuildItem> syntheticBeans,
3937
BeanRegistrationPhaseBuildItem beanRegistration, BuildProducer<BeanConfiguratorBuildItem> configurators) {
4038

41-
Map<String, Function<SyntheticCreationalContext<?>, ?>> creationFunctions = new HashMap<>();
42-
Map<String, Supplier<ActiveResult>> checkActiveSuppliers = new HashMap<>();
39+
Map<String, Function<SyntheticCreationalContext<?>, ?>> creationFunctions = new LinkedHashMap<>();
40+
Map<String, Supplier<ActiveResult>> checkActiveSuppliers = new LinkedHashMap<>();
4341

4442
for (SyntheticBeanBuildItem bean : syntheticBeans) {
4543
if (bean.hasRecorderInstance() && bean.isStaticInit()) {
@@ -56,8 +54,8 @@ void initStatic(ArcRecorder recorder, List<SyntheticBeanBuildItem> syntheticBean
5654
ServiceStartBuildItem initRuntime(ArcRecorder recorder, List<SyntheticBeanBuildItem> syntheticBeans,
5755
BeanRegistrationPhaseBuildItem beanRegistration, BuildProducer<BeanConfiguratorBuildItem> configurators) {
5856

59-
Map<String, Function<SyntheticCreationalContext<?>, ?>> creationFunctions = new HashMap<>();
60-
Map<String, Supplier<ActiveResult>> checkActiveSuppliers = new HashMap<>();
57+
Map<String, Function<SyntheticCreationalContext<?>, ?>> creationFunctions = new LinkedHashMap<>();
58+
Map<String, Supplier<ActiveResult>> checkActiveSuppliers = new LinkedHashMap<>();
6159

6260
for (SyntheticBeanBuildItem bean : syntheticBeans) {
6361
if (bean.hasRecorderInstance() && !bean.isStaticInit()) {
@@ -83,7 +81,7 @@ private void configureSyntheticBean(ArcRecorder recorder,
8381
Map<String, Function<SyntheticCreationalContext<?>, ?>> creationFunctions,
8482
Map<String, Supplier<ActiveResult>> checkActiveSuppliers, BeanRegistrationPhaseBuildItem beanRegistration,
8583
SyntheticBeanBuildItem bean) {
86-
String name = createName(bean.configurator());
84+
String name = bean.name();
8785
if (bean.configurator().getRuntimeValue() != null) {
8886
creationFunctions.put(name, recorder.createFunction(bean.configurator().getRuntimeValue()));
8987
} else if (bean.configurator().getSupplier() != null) {
@@ -105,12 +103,6 @@ private void configureSyntheticBean(ArcRecorder recorder,
105103
configurator.done();
106104
}
107105

108-
private String createName(ExtendedBeanConfigurator configurator) {
109-
return configurator.getImplClazz().toString().replace(".", "_") + "_"
110-
+ HashUtil.sha1(configurator.getTypes().toString() + configurator.getQualifiers().toString()
111-
+ (configurator.getIdentifier() != null ? configurator.getIdentifier() : ""));
112-
}
113-
114106
private Consumer<BeanConfiguratorBase.CreateGeneration> creator(String name, SyntheticBeanBuildItem bean) {
115107
return new Consumer<BeanConfiguratorBase.CreateGeneration>() {
116108
@Override

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ValueRegistryProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.quarkus.arc.deployment;
22

3+
import java.util.Comparator;
34
import java.util.HashSet;
45
import java.util.ServiceLoader;
56
import java.util.Set;
@@ -42,7 +43,7 @@ void runtimeInfo(
4243
ValueRegistryRecorder recorder,
4344
BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {
4445

45-
for (Class<?> runtimeInfo : getRuntimeInfoClasses()) {
46+
for (Class<?> runtimeInfo : getRuntimeInfoClasses().stream().sorted(Comparator.comparing(Class::getName)).toList()) {
4647
SyntheticBeanBuildItem.ExtendedBeanConfigurator configurator = SyntheticBeanBuildItem
4748
.configure(runtimeInfo)
4849
.startup()

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,8 +1337,9 @@ public BlockCreator checkActiveMethod() {
13371337
.append(implClassName)
13381338
.append("'\n");
13391339
msgBuilder.append("This bean is injected into:");
1340-
for (InjectionPointInfo matchingIP : matchingIPs) {
1341-
msgBuilder.append("\n\t- ").append(matchingIP.getTargetInfo());
1340+
for (String matchingTargetInfo : matchingIPs.stream().map(InjectionPointInfo::getTargetInfo).sorted()
1341+
.toList()) {
1342+
msgBuilder.append("\n\t- ").append(matchingTargetInfo);
13421343
}
13431344
}
13441345
b1.throw_(InactiveBeanException.class, b1.exprToString(msg));

0 commit comments

Comments
 (0)