E
E
Eugene2017-02-10 10:49:06
Spring
Eugene, 2017-02-10 10:49:06

How to replace one implementation with another in the list of similar beans?

Hello.
I stumbled upon this case and thought about it.
See. I have a SimpleBean interface, for example.

package com.example.beans;

public interface SimpleBean {

    String getName();
}

There are three implementations of this interface: FirstBean, SecondBean, and ThirdBean, respectively.
package com.example.beans;

import org.springframework.stereotype.*;

@Component
public class FirstBean implements SimpleBean {
    @Override
    public String getName() {
        return "First Bean";
    }
}

package com.example.beans;

import org.springframework.stereotype.*;

@Component
public class SecondBean implements SimpleBean {
    @Override
    public String getName() {
        return "Second Bean";
    }
}

package com.example.beans;

import org.springframework.stereotype.*;

@Component
@Primary
public class ThirdBean extends FirstBean {

    @Override
    public String getName() {
        return "I'm inherited " + super.getName() + " and my name is Third Bean";
    }
}

The ThirdBean mate differs from the rest in that it does not directly implement SimpleBean, but inherits FirstBean.
There is a certain controller, let's call it DemoController:
package com.example.controllers;

import com.example.beans.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@Controller
public class DemoController {

    private List<SimpleBean> myBeans;

    /** */
    @Autowired
    public DemoController(List<SimpleBean> myBeans) {
        this.myBeans = myBeans;
    }

    /** */
    @RequestMapping("/")
    @ResponseBody
    public String hello() {
        StringBuilder beansNames = new StringBuilder();
        myBeans.forEach(bean -> beansNames.append(bean.getName()).append("\n"));
        return beansNames.toString();
    }
}

As you can see, the list from the SimpleBean is injected into the controller via the constructor.
Actually, the case is that there is no FirstBean in this list, because it is inherited by ThirdBean.
Now a list of all three bins is being implemented. The @Primary annotation on ThirdBean does not solve the problem.
Maybe someone solved a similar problem, tell me in which direction to dig?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexander Kosarev, 2017-02-13
@zolt85

There is an annotation @Conditional for this. If Spring Boot is used, then it has @ConditionalOnMissingClass, which allows you to specify that the marked bean should be created if the specified class is not found:

@ConditionalOnMissingClass(ThirdBean.class)
@Component
public class FirstBean implements SimpleBean {
    @Override
    public String getName() {
        return "First Bean";
    }
}

L
LooksWorking, 2017-03-13
@LooksWorking

Profiles don't work?
Annotate your implementers
with @Profile("SimpleBean-third")
And specify active profiles on startup, the corresponding SimpleBean implementation will be injected.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question