I am trying to extend existing code which auto-wires a number of components which share the same base class and are only referred to by their base class, ei:
@Configuration
public class NavigationHotKeyBindConfigs {
private static final Logger logger = LogManager.getLogger(NavigationHotKeyBindConfigs.class);
@Autowired
private HotKeyConfig hotKeyConfig;
@Autowired
private ANavigation upNavigation;
@Autowired
private ANavigation downNavigation;
@Autowired
private ANavigation centerOnSelection;
@Autowired
private ANavigation handVerify;
public abstract class ANavigation {
@Autowired
protected ScrollSchedulerConfigurer scrollSchedulerConfigurer;
public abstract void execute(DetectionView DetectionView);
}
@Component
public class DownNavigation extends ANavigation{
private static final Logger logger = LogManager.getLogger(DownNavigation.class);
public void execute(DetectionView detectionView){
logger.info(String.format("Received: Navigation key %s", ENavigationKey.DOWN.name()));
scrollSchedulerConfigurer.stop();
detectionView.selectNextDetection();
}
}
@Component
public class UpNavigation extends ANavigation{
private static final Logger logger = LogManager.getLogger(UpNavigation.class);
public void execute(DetectionView detectionView){
logger.info(String.format("Received: Navigation key %s", ENavigationKey.Up.name()));
scrollSchedulerConfigurer.stop();
detectionView.selectPrevDetection();
}
}
I don't understand how spring is ever supposed to match up upNavigation/downNavigation with the UpNavigation/DownNavigation components respectively. Was this just bad design from the original author or is there a subtlety I'm missing?
This lack of understanding is also causing some issues as the centerOnSelection and handVerify objects end up NULL after autowiring though they follow the same pattern in every way I can see. Interestingly, this last behavior is different when run in the intellij IDE vs when run out of a .jar
CodePudding user response:
You can do it like this ...
Let's say we have two beans which have the same base class or interface
@Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
Then we inject them like this ...
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
}
From the point of view of clarity and maintainability this seems to be the best solution
CodePudding user response:
@Autowired
first looks at the type of the variable and then the name of the variable to match the correct bean. By default, the name of a class marked with @Component
is its short name, e.g. upNavigation
for the UpNavigation
class.
@Autowired
private ANavigation upNavigation;
is the same as
@Autowired
@Qualifier("upNavigation")
private ANavigation upNavigation;
And
@Component
public class UpNavigation
is the same as
@Component("upNavigation")
public class UpNavigation
Since the names match, Spring is able to find the corresponding bean.