This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push: new 6fac2e5962 [MNG-8764] Sort injected lists by @Priority annotation (#2425) 6fac2e5962 is described below commit 6fac2e5962ee54be892fff7505a86d0d01277b38 Author: Guillaume Nodet <gno...@gmail.com> AuthorDate: Wed Jun 4 11:05:16 2025 +0200 [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 --- .../org/apache/maven/di/impl/InjectorImpl.java | 8 ++- .../org/apache/maven/di/impl/InjectorImplTest.java | 70 ++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java index 266122ef31..c93ccb5d1d 100644 --- a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java +++ b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java @@ -220,7 +220,13 @@ public <Q> Supplier<Q> doGetCompiledBinding(Dependency<Q> dep) { if (key.getRawType() == List.class) { Set<Binding<Object>> res2 = getBindings(key.getTypeParameter(0)); if (res2 != null) { - List<Supplier<Object>> list = res2.stream().map(this::compile).collect(Collectors.toList()); + // Sort bindings by priority (highest first) for deterministic ordering + List<Binding<Object>> sortedBindings = new ArrayList<>(res2); + Comparator<Binding<Object>> comparing = Comparator.comparing(Binding::getPriority); + sortedBindings.sort(comparing.reversed()); + + List<Supplier<Object>> list = + sortedBindings.stream().map(this::compile).collect(Collectors.toList()); //noinspection unchecked return () -> (Q) list(list, Supplier::get); } diff --git a/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java b/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java index 2c6b46e892..f02eb011d9 100644 --- a/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java +++ b/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java @@ -202,6 +202,20 @@ void injectListTest() { assertNotSame(services.get(0).getClass(), services.get(1).getClass()); } + @Test + void injectListWithPriorityTest() { + Injector injector = Injector.create().bindImplicit(InjectListWithPriority.class); + List<InjectListWithPriority.MyService> services = + injector.getInstance(new Key<List<InjectListWithPriority.MyService>>() {}); + assertNotNull(services); + assertEquals(3, services.size()); + + // Verify services are ordered by priority (highest first) + assertInstanceOf(InjectListWithPriority.HighPriorityServiceImpl.class, services.get(0)); + assertInstanceOf(InjectListWithPriority.MediumPriorityServiceImpl.class, services.get(1)); + assertInstanceOf(InjectListWithPriority.LowPriorityServiceImpl.class, services.get(2)); + } + static class InjectList { interface MyService {} @@ -213,6 +227,23 @@ static class MyServiceImpl implements MyService {} static class AnotherServiceImpl implements MyService {} } + static class InjectListWithPriority { + + interface MyService {} + + @Named + @Priority(100) + static class HighPriorityServiceImpl implements MyService {} + + @Named + @Priority(50) + static class MediumPriorityServiceImpl implements MyService {} + + @Named + @Priority(10) + static class LowPriorityServiceImpl implements MyService {} + } + @Test void injectMapTest() { Injector injector = Injector.create().bindImplicit(InjectMap.class); @@ -392,6 +423,25 @@ void testCircularPriorityDependency() { .hasMessageContaining("MyService"); } + @Test + void testListInjectionWithMixedPriorities() { + Injector injector = Injector.create().bindImplicit(MixedPriorityTest.class); + List<MixedPriorityTest.MyService> services = + injector.getInstance(new Key<List<MixedPriorityTest.MyService>>() {}); + assertNotNull(services); + assertEquals(4, services.size()); + + // Verify services are ordered by priority (highest first) + // Priority 200 (highest) + assertInstanceOf(MixedPriorityTest.VeryHighPriorityServiceImpl.class, services.get(0)); + // Priority 100 + assertInstanceOf(MixedPriorityTest.HighPriorityServiceImpl.class, services.get(1)); + // Priority 50 + assertInstanceOf(MixedPriorityTest.MediumPriorityServiceImpl.class, services.get(2)); + // No priority annotation (default 0) + assertInstanceOf(MixedPriorityTest.DefaultPriorityServiceImpl.class, services.get(3)); + } + static class CircularPriorityTest { interface MyService {} @@ -405,4 +455,24 @@ static class HighPriorityServiceImpl implements MyService { MyService defaultService; // This tries to inject the default implementation } } + + static class MixedPriorityTest { + + interface MyService {} + + @Named + @Priority(200) + static class VeryHighPriorityServiceImpl implements MyService {} + + @Named + @Priority(100) + static class HighPriorityServiceImpl implements MyService {} + + @Named + @Priority(50) + static class MediumPriorityServiceImpl implements MyService {} + + @Named + static class DefaultPriorityServiceImpl implements MyService {} + } }