Spring ordered list of beans
Asked Answered
S

5

29

I have several beans that implement the same interface. Each bean is annotated with

@Component 
@Order(SORT_ORDER).
public class MyClass implements BeanInterface{
    ...
}

At one point I autowire a list of components and I expect a sorted list of beans. The list of beans is not sorted according the orders I have set with the annotation.

I tried implementing the interface Ordered and the same behaviour occurs.

@Component
public class Factory{


    @Autowired
    private List<BeanInterface> list; // <- I expect a sorted list here
    ...
}

Am I doing anything wrong?

Sutra answered 6/6, 2013 at 17:0 Comment(0)
S
26

I found a solution to the issue, as you say, this annotation is not meant for that despite it would be a nice feature.

To make it work this way its just necessary to add the following code in the bean containing the sorted list.

@PostConstruct
public void init() {
    Collections.sort(list,AnnotationAwareOrderComparator.INSTANCE);
}

Hope it helps.

Sutra answered 7/6, 2013 at 9:56 Comment(1)
Is this still the case with Spring 4?Hisakohisbe
L
42

Ordering autowired collections is supported since Spring 4.

See: Spring 4 Ordering Autowired Collections

Summary: if you add @Order(value=1), @Order(value=2)... to your bean definitions, they will be injected in a collection ordered according to the value parameter. This is not the same as declaring that you want the collection in natural order - for that you have to explicitly sort the list yourself after receiving it, as per Jordi P.S.'s answer.

Landscapist answered 5/3, 2015 at 17:50 Comment(2)
this is useful for many people but doesn't answer the actual question. Also it's best to put the info in the answer itself in case the blog disappears. I edited to add a summary.Ossein
Link to the official Spring 5 docs.Clover
S
26

I found a solution to the issue, as you say, this annotation is not meant for that despite it would be a nice feature.

To make it work this way its just necessary to add the following code in the bean containing the sorted list.

@PostConstruct
public void init() {
    Collections.sort(list,AnnotationAwareOrderComparator.INSTANCE);
}

Hope it helps.

Sutra answered 7/6, 2013 at 9:56 Comment(1)
Is this still the case with Spring 4?Hisakohisbe
B
1

For Spring versions < 4, the @Order annotation is used to specify the order in which AOP advice is executed, it doesn't sort lists. To achieve sorting on your list have your BeanInterface classes implement the Comparable interface and override the compareTo method to specify how the objects should be sorted. Then you can sort the list using Collections.sort(list). Assuming BeanInterface has a method called getSortOrder that returns an Integer object specifying the object's sort order, you could do something like this:

@Component 
public class MyClass implements BeanInterface, Comparable<BeanInterface> {
    public Integer getSortOrder() {
        return sortOrder;
    }

    public int compareTo(BeanInterface other) {
        return getSortOrder().compareTo(other.getSortOrder());
    }
}

Then you can sort the list like this:

Collections.sort(list);
Breechblock answered 6/6, 2013 at 20:35 Comment(3)
This answer seems valid only for spring < 4Resignation
@Resignation I guess that makes sense since the answer was posted in June of 2013, long before Spring 4 existed.Breechblock
Just scope it like "For Spring Versions before 4" or so to fix.Resignation
O
1

There is a jira issue about that feature in spring. I have added an implementation of beanfactory in the comment which im currently using to support that feature:

https://jira.springsource.org/browse/SPR-5574

Otherness answered 7/6, 2013 at 5:28 Comment(0)
I
0

@Order annotation is here for rescue.

I am using SpringBoot 2.6.1 and its a working code snippet for me without adding any @PostConstruct to apply the sorting explicitely.

interface MyFilter {
  
}

Below are multiple implementations for the interface

@Order(value=1)
public class MyFilterImpl1 implements MyFilter {
} 


@Order(value=2)
public class MyFilterImpl2 implements MyFilter {
} 


@Order(value=3)
public class MyFilterImpl3 implements MyFilter {
} 

And below is the class where the list of MyFilter implementation needs to be injected.

@Component
    @RequiredArgConstructor
    public class MyBean {
     private final List<MyFilter> myFilters;
    }
Ieper answered 23/2, 2022 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.