javaspring-bootfactory-pattern

How to dynamically order the implementation list of a interface with default value in Spring Boot?


I have an interface which extends java.util.function.Function, there are 2 further implementation of the interface lets say class A, B which implements the interface Base;

interface Base extends Function<Object, Object> {

  @Override
  default Object apply(Object object) {
    return object;     // simply do nothing
  }

  default boolean accept(String str) {
    return true;     // for choosing the right instance
  }
}
@Service
class A implements Base {

  String validationString = "some-random-string";

  @Override
  public Object apply(Object object) {
    // update the object ....
    return object;
  }

  @Override
  public boolean accept(String str) {
    return str.equals(validationString);
  }
}
@Service
class B implements Base {

  String validationString = "some-random-string-2";

  @Override
  public Object apply(Object object) {
    // update the object ....
    return object;
  }

  @Override
  public boolean accept(String str) {
    return str.equals(validationString);
  }
}
@Service
@RequiredArgsConstructor
class SomeService {

  List<Base> baseList;

  public void callingClass(String str) {

    // in below 
    // I want to order it in such a way that 
    // if str matches A.validationString then give back A's instance
    // else if str matches B.validationString then give back B's instance
    // else return Base's instance
    Base base = baseList.stream()
        .filter(baseImpl -> baseImpl.accept(str))
        .findFirst().orElseThrow();

  }
}

So, what I am trying to achieve, if there is any way from which I don't have to manually create a Factory Class (Factory Pattern) and dynamically Filter the instance A, B using accept() and if none find then return instance of Base (as default).

Can anybody help with this?


Solution

  • Combining @k314159 and @atish.s solution and improving on that:

    Expose the DefaultBase class as another bean, but add @Order annotation to put it last in list

    @Component
    @Order(Precedence.LAST)
    class DefaultBase implements Base {
        default accepts(Object obj){
            return true;
        }
    }
    

    Then changing the Service method to this:

    public Base callingClass(String str) { 
        return baseList.stream()
            .filter(baseImpl -> baseImpl.accept(str))
            .findFirst()
            .orElseThrow();
    }