Skip to content

Commit 6fac2e5

Browse files
authored
[MNG-8764] Sort injected lists by @priority annotation (#2425)
When injecting List<T> dependencies, the DI container now sorts the bindings by their @priority annotation value in descending order (highest priority first) to ensure deterministic ordering. This change ensures that components with higher priority values appear first in injected lists, providing predictable behavior for dependency injection scenarios where order matters. - Modified InjectorImpl.doGetCompiledBinding() to sort bindings by priority before creating supplier lists - Added comprehensive tests for priority-based list ordering - Includes tests for mixed priorities and default priority handling
1 parent 33a6ffe commit 6fac2e5

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,13 @@ public <Q> Supplier<Q> doGetCompiledBinding(Dependency<Q> dep) {
220220
if (key.getRawType() == List.class) {
221221
Set<Binding<Object>> res2 = getBindings(key.getTypeParameter(0));
222222
if (res2 != null) {
223-
List<Supplier<Object>> list = res2.stream().map(this::compile).collect(Collectors.toList());
223+
// Sort bindings by priority (highest first) for deterministic ordering
224+
List<Binding<Object>> sortedBindings = new ArrayList<>(res2);
225+
Comparator<Binding<Object>> comparing = Comparator.comparing(Binding::getPriority);
226+
sortedBindings.sort(comparing.reversed());
227+
228+
List<Supplier<Object>> list =
229+
sortedBindings.stream().map(this::compile).collect(Collectors.toList());
224230
//noinspection unchecked
225231
return () -> (Q) list(list, Supplier::get);
226232
}

impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,20 @@ void injectListTest() {
202202
assertNotSame(services.get(0).getClass(), services.get(1).getClass());
203203
}
204204

205+
@Test
206+
void injectListWithPriorityTest() {
207+
Injector injector = Injector.create().bindImplicit(InjectListWithPriority.class);
208+
List<InjectListWithPriority.MyService> services =
209+
injector.getInstance(new Key<List<InjectListWithPriority.MyService>>() {});
210+
assertNotNull(services);
211+
assertEquals(3, services.size());
212+
213+
// Verify services are ordered by priority (highest first)
214+
assertInstanceOf(InjectListWithPriority.HighPriorityServiceImpl.class, services.get(0));
215+
assertInstanceOf(InjectListWithPriority.MediumPriorityServiceImpl.class, services.get(1));
216+
assertInstanceOf(InjectListWithPriority.LowPriorityServiceImpl.class, services.get(2));
217+
}
218+
205219
static class InjectList {
206220

207221
interface MyService {}
@@ -213,6 +227,23 @@ static class MyServiceImpl implements MyService {}
213227
static class AnotherServiceImpl implements MyService {}
214228
}
215229

230+
static class InjectListWithPriority {
231+
232+
interface MyService {}
233+
234+
@Named
235+
@Priority(100)
236+
static class HighPriorityServiceImpl implements MyService {}
237+
238+
@Named
239+
@Priority(50)
240+
static class MediumPriorityServiceImpl implements MyService {}
241+
242+
@Named
243+
@Priority(10)
244+
static class LowPriorityServiceImpl implements MyService {}
245+
}
246+
216247
@Test
217248
void injectMapTest() {
218249
Injector injector = Injector.create().bindImplicit(InjectMap.class);
@@ -392,6 +423,25 @@ void testCircularPriorityDependency() {
392423
.hasMessageContaining("MyService");
393424
}
394425

426+
@Test
427+
void testListInjectionWithMixedPriorities() {
428+
Injector injector = Injector.create().bindImplicit(MixedPriorityTest.class);
429+
List<MixedPriorityTest.MyService> services =
430+
injector.getInstance(new Key<List<MixedPriorityTest.MyService>>() {});
431+
assertNotNull(services);
432+
assertEquals(4, services.size());
433+
434+
// Verify services are ordered by priority (highest first)
435+
// Priority 200 (highest)
436+
assertInstanceOf(MixedPriorityTest.VeryHighPriorityServiceImpl.class, services.get(0));
437+
// Priority 100
438+
assertInstanceOf(MixedPriorityTest.HighPriorityServiceImpl.class, services.get(1));
439+
// Priority 50
440+
assertInstanceOf(MixedPriorityTest.MediumPriorityServiceImpl.class, services.get(2));
441+
// No priority annotation (default 0)
442+
assertInstanceOf(MixedPriorityTest.DefaultPriorityServiceImpl.class, services.get(3));
443+
}
444+
395445
static class CircularPriorityTest {
396446
interface MyService {}
397447

@@ -405,4 +455,24 @@ static class HighPriorityServiceImpl implements MyService {
405455
MyService defaultService; // This tries to inject the default implementation
406456
}
407457
}
458+
459+
static class MixedPriorityTest {
460+
461+
interface MyService {}
462+
463+
@Named
464+
@Priority(200)
465+
static class VeryHighPriorityServiceImpl implements MyService {}
466+
467+
@Named
468+
@Priority(100)
469+
static class HighPriorityServiceImpl implements MyService {}
470+
471+
@Named
472+
@Priority(50)
473+
static class MediumPriorityServiceImpl implements MyService {}
474+
475+
@Named
476+
static class DefaultPriorityServiceImpl implements MyService {}
477+
}
408478
}

0 commit comments

Comments
 (0)